組合模式(Composite Pattern)
概念:
定義:組合模式 允許你將對象組合成樹型結構來表現“整體/部分”層次結構。組合能讓客戶以一致的方式處理個別對象以及對象組合。在大多數情況下,我們可以忽略對象組合和個別對象之間的差別。
在日常生活中我們經常會遇到樹型結構的問題,比如典型的公司管理,上司管理不同的下屬,下屬也可能屬於某個部門的上司。
組合模式可以模糊簡單元素和複雜元素的概念,客戶程序可以向處理簡單元素一樣來處理複雜元素,從而使得客戶程序與複雜元素的內部結構解耦。
組成:
Component(組合):爲組合中的所有對象定義一個接口。包括組合和葉節點。
Leaf(葉節點):葉節點通過實現了 Composite 支持的操作,定義了這內元素的行爲。
Composite(組件):定義組件的行爲,並且組件也擁有子節點。
例子:
公司僱員例子,CEO 有僱員,僱員中有部門經理,經理地面又有僱員。
組件類:
所有的組件都必須實現該接口,然而葉節點和組合節點的角色不同,所以有些方法可能並不適合某種節點。遇到這種情況時,有時候最好的方式是拋出運行時異常。
public abstract class EmployeeConponent {
private String name;
private String description;
private double salary;
//構造函數,包括姓名、描述、薪水
public EmployeeConponent(String name, String description, double salary) {
this.name = name;
this.description = description;
this.salary = salary;
}
//添加僱員
public void add(EmployeeConponent employeeConponent) {
throw new UnsupportedOperationException();
}
//刪除僱員
public void remove(EmployeeConponent employeeConponent) {
throw new UnsupportedOperationException();
}
//獲得某一個子節點
public Object getChild(int i) {
throw new UnsupportedOperationException();
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public double getSalary() {
return salary;
}
public void print() {
System.out.print("name:" + name);
System.out.print(" description:" + description);
System.out.println(" salary:" + salary);
}
}
Boss 類:
public class Boss extends EmployeeConponent {
//僱員列表
ArrayList<EmployeeConponent> subordinates;
public Boss(String name, String description, double salary) {
super(name, description, salary);
subordinates = new ArrayList<EmployeeConponent>();
}
@Override
public void add(EmployeeConponent employeeConponent) {
subordinates.add(employeeConponent);
}
@Override
public void remove(EmployeeConponent employeeConponent) {
subordinates.remove(employeeConponent);
}
@Override
public EmployeeConponent getChild(int i) {
return (EmployeeConponent) subordinates.get(i);
}
//打印自己以及僱員
@Override
public void print() {
System.out.print("name:" + super.getName());
System.out.print(" description:" + super.getDescription());
System.out.println(" salary:" + super.getSalary());
for (EmployeeConponent i : subordinates) {
i.print();
}
System.out.println();
}
}
僱員類:
public class Employee extends EmployeeConponent {
public Employee(String name, String description, double salary) {
super(name, description, salary);
}
}
測試類:
public class Client {
public static void main(String[] args) {
Boss CEO = new Boss("Li", "CEO", 25000);
Employee employee1 = new Employee("Zhang", "Employee", 12000);
Employee employee2 = new Employee("Zhao", "Employee", 12000);
Boss manager = new Boss("Wang", "Manager", 20000);
Employee employee3 = new Employee("He", "Employee", 12000);
Employee employee4 = new Employee("Qi", "Empoyee", 12000);
CEO.add(employee1);
CEO.add(employee2);
CEO.add(manager);
manager.add(employee3);
manager.add(employee4);
CEO.print();
}
}
適用場景:
- 當我們想表示對象的部分-整體層次結構(樹形結構,如文件系統、僱員關係等)。
- 希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
- 組合模式解耦了客戶程序與複雜元素內部結構,從而使客戶程序可以向處理簡單元素一樣來處理複雜元素。
如果你想要創建層次結構,並可以在其中以相同的方式對待所有元素,那麼組合模式就是最理想的選擇。
優缺點:
優點:
- 高層模塊調用簡單,組合模式解耦了客戶程序與複雜元素內部結構。從而使客戶程序可以向處理簡單元素一樣來處理複雜元素。創建層次結構,並可以在其中以相同的方式對待所有元素。
- 節點可以自由增加。
缺點:
- 在使用組合模式時,其葉子和樹枝的聲明都是實現類,而不是接口,違反了依賴倒置原則。
依賴倒置原則:要依賴抽象,不要依賴具體類。
這個原則說明:不能讓高層組件依賴底層組件,而且,不管是高層組件或底層組件,都應該依賴於抽象。