組合模式(Composite Pattern),又叫部分整體模式,是用于把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及整體層次。這種類型的設計模式屬于結構型模式,它建立了對象組的樹形結構。這種模式建立了一個包含自己對象組的類。該類提供了修改相同對象組的方式。
大話設計模式中程傑老師給出的定義是,組合模式:将對象組合成樹形結構以表示”部分-整體”的層次結構。組合模式使得使用者對單個對象群組合對象的使用具有一緻性。
組合模式結構圖:
首先,讓我們通過過一個簡單的執行個體來簡單了解一下組合模式做基本的用法。執行個體示範了一個組織中員工的層次結構。
建立Employee類:
package com.exercise.composite;
import java.util.ArrayList;
import java.util.List;
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;//部下
//constructor
public Employee(String name, String dept, int salary,
List<Employee> subordinates) {
super();
this.name = name;
this.dept = dept;
this.salary = salary;
this.subordinates = subordinates;
subordinates = new ArrayList<Employee>();
}
public Employee(String name, String dept, int salary) {
super();
this.name = name;
this.dept = dept;
this.salary = salary;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e){
subordinates.add(e);
}
public void remove(Employee e){
subordinates.remove(e);
}
public List<Employee> getSubordinates(){
return subordinates;
}
public String toString(){
return "Employee :[ Name : " + name
+ ", dept : " + dept + ", salary :"
+ salary + " ]";
}
}
測試類:
package com.exercise.composite;
/**
* 使用Employee來建立和列印員工的層次結構
* @author lmb
*
*/
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", );
Employee headSales = new Employee("Robert","Head Sales", );
Employee headMarketing = new Employee("Michel","Head Marketing", );
Employee clerk1 = new Employee("Laura","Marketing", );
Employee clerk2 = new Employee("Bob","Marketing", );
Employee salesExecutive1 = new Employee("Richard","Sales", );
Employee salesExecutive2 = new Employee("Rob","Sales", );
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
headMarketing.add(clerk1);
headMarketing.add(clerk2);
//列印該組織的所有員工
System.out.println("-------------------公司員工情況----------------------");
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
//列印CEO的直屬一級部下
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
//列印CEO的二級部下
System.out.println(employee);
}
}
}
}
運作結果:
使用場景:
需求中是展現部分與整體層次結構的時候,以及當我們希望使用者可以忽略組合對象與單個對象的不同,統一的使用組合結構中的所有對象時。簡而言之,就是涉及到部分、整體場景時,如樹形菜單,檔案、檔案夾的管理。
主要解決:它在我們樹型結構的問題中,模糊了簡單元素和複雜元素的概念,客戶程式可以向處理簡單元素一樣來處理複雜元素,進而使得客戶程式與複雜元素的内部結構解耦。
如何解決:樹枝和葉子實作統一接口,樹枝内部組合該接口。
一般在工作中說起部分和總體我們想到最多的大概就是總公司和分公司了,如果我們需要做一套辦公管理系統,并且總公司的人力資源部、财務部等的辦公挂曆功能在所有的分公司也都要有,我們該怎麼實作?
功能實作:
抽象公司類或接口
package com.composite;
public abstract class Company {
protected String name;
public Company(String name){
this.name = name;
}
public abstract void add(Company company);//add
public abstract void remove(Company company);//remove
public abstract void display(int depth);//display
public abstract void lineofDuty();//line of duty
}
具體公司類(樹枝節點)
package com.composite;
import java.util.ArrayList;
import java.util.List;
public class ConcreteCompany extends Company {
private List<Company> childrenCompany = new ArrayList<Company>();
public ConcreteCompany(String name) {
super(name);
}
@Override
public void add(Company company) {
childrenCompany.add(company);
}
@Override
public void display(int depth) {
System.out.println("第 " + depth + " 層的機構名為: " + name);
for (Company c : childrenCompany) {
c.display(depth + );
}
}
@Override
public void lineofDuty() {
for (Company c : childrenCompany) {
c.lineofDuty();
}
}
@Override
public void remove(Company company) {
childrenCompany.remove(company);
}
}
财務部和人力資源部(樹葉節點)
package com.composite;
public class HRDepartment extends Company {
public HRDepartment(String name) {
super(name);
}
@Override
public void add(Company company) {
}
@Override
public void display(int depth) {
System.out.println("第 " + depth + " 層的機構名為: " + name);
}
@Override
public void lineofDuty() {
System.out.println(name + " 負責員工招聘管理教育訓練");
}
@Override
public void remove(Company company) {
}
}
package com.composite;
public class FinanceDepartment extends Company {
public FinanceDepartment(String name) {
super(name);
}
@Override
public void add(Company company) {
}
@Override
public void display(int depth) {
System.out.println("第 " + depth + " 層的機構名為: " + name);
}
@Override
public void lineofDuty() {
System.out.println(name + " 負責公司财務收支管理");
}
@Override
public void remove(Company company) {
}
}
測試方法
package com.composite;
public class CompositePatternDemo {
public static void main(String[] args) {
//一個總公司
ConcreteCompany root = new ConcreteCompany("北京總公司");
root.add(new HRDepartment("總公司人力資源部"));
root.add(new FinanceDepartment("總公司财務部"));
//三個子公司
ConcreteCompany com1 = new ConcreteCompany("廣州分公司");
com1.add(new HRDepartment("廣州分公司人力資源部"));
com1.add(new FinanceDepartment("廣州分公司财務部"));
root.add(com1);
ConcreteCompany com2 = new ConcreteCompany("杭州分公司");
com2.add(new HRDepartment("杭州分公司人力資源部"));
com2.add(new FinanceDepartment("杭州分公司财務部"));
root.add(com2);
ConcreteCompany com3 = new ConcreteCompany("深圳分公司");
com3.add(new HRDepartment("深圳分公司人力資源部"));
com3.add(new FinanceDepartment("深圳分公司财務部"));
root.add(com3);
System.out.println("-------公司結構圖--------");
root.display();
System.out.println("----------各部門職責----------");
root.lineofDuty();
}
}
運作結果:
這樣,通過組合模式我們就定義了包含人力資源部和财務部這些基本對象和分公司等組合對象的類層次結構。
基本對象可以被組合成更複雜的組合對象,而這個組合對象又可以被組合,這樣不斷的遞歸下去,在客戶代碼中,任何用到基本對象的地方都可以使用組合對象了。組合模式讓客戶可以一緻的使用組合結構和單個對象。
應用執行個體:
1、算術表達式包括操作數、操作符和另一個操作數,其中,另一個操作符也可以是操作樹、操作符和另一個操作數。
2、在 JAVA AWT 和 SWING 中,對于 Button 和 Checkbox 是樹葉,Container 是樹枝。
優點:
1、高層子產品調用簡單。
2、節點自由增加。
缺點:
在使用組合模式時,其葉子和樹枝的聲明都是實作類,而不是接口,違反了依賴倒置原則。