注:示例來自《大話設計模式》
假如現有如下場景 給一家大公司做辦公管理系統 總部有人力資源 财務 營運等部門 還有一些分公司 現在有個需求 總公司的人力資源部 财務部等辦公管理功能在所有的分公司都需要有 這其實就是整體與部分可以被一緻對待的問題 下面我們使用組合模式進行簡單實作 代碼如下
公司類
package Test19;
public abstract class Company {
protected String name;
public Company(String name)
{
this.name = name;
}
public abstract void Add(Company c);//增加
public abstract void Remove(Company c);//移除
public abstract void Display(int depth);//顯示
public abstract void LineOfDuty();//履行職責
}
具體公司類
package Test19;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class ConcreteCompany extends Company {
private List<Company> children = new ArrayList<Company>();
public ConcreteCompany(String name) {
super(name);
}
@Override
public void Add(Company c) {
children.add(c);
}
@Override
public void Remove(Company c) {
children.remove(c);
}
@Override
public void Display(int depth) {
System.out.println(StringUtils.repeat("-", depth) + name);
for (Company component : children)
{
component.Display(depth + );
}
}
@Override
public void LineOfDuty() {
for (Company component : children)
{
component.LineOfDuty();
}
}
}
人力資源部與财務部類
package Test19;
import org.apache.commons.lang.StringUtils;
//人力資源部
public class HRDepartment extends Company {
public HRDepartment(String name) {
super(name);
}
@Override
public void Add(Company c) {
}
@Override
public void Remove(Company c) {
}
@Override
public void Display(int depth) {
System.out.println(StringUtils.repeat("-", depth) + name);
}
@Override
public void LineOfDuty() {
System.out.println(name+" 員工招聘教育訓練管理");
}
}
package Test19;
import org.apache.commons.lang.StringUtils;
//财務部
public class FinanceDepartment extends Company {
public FinanceDepartment(String name) {
super(name);
}
@Override
public void Add(Company c) {
}
@Override
public void Remove(Company c) {
}
@Override
public void Display(int depth) {
System.out.println(StringUtils.repeat("-", depth) + name);
}
@Override
public void LineOfDuty() {
System.out.println(name+" 公司财務收支管理");
}
}
用戶端代碼
package Test19;
public class Program {
public static void main(String[] args) {
ConcreteCompany root = new ConcreteCompany("北京總公司");
root.Add(new HRDepartment("總公司人力資源部"));
root.Add(new FinanceDepartment("總公司财務部"));
ConcreteCompany comp = new ConcreteCompany("上海華東分公司");
comp.Add(new HRDepartment("華東分公司人力資源部"));
comp.Add(new FinanceDepartment("華東分公司财務部"));
root.Add(comp);
ConcreteCompany comp1 = new ConcreteCompany("南京辦事處");
comp1.Add(new HRDepartment("南京辦事處人力資源部"));
comp1.Add(new FinanceDepartment("南京辦事處财務部"));
comp.Add(comp1);
ConcreteCompany comp2 = new ConcreteCompany("杭州辦事處");
comp2.Add(new HRDepartment("杭州辦事處人力資源部"));
comp2.Add(new FinanceDepartment("杭州辦事處财務部"));
comp.Add(comp2);
System.out.println("\n結構圖:");
root.Display();
System.out.println("\n職責:");
root.LineOfDuty();
}
}
組合模式 将對象組合成樹形結構以表示 部分-整體 的層次結構 組合模式使得使用者對單個對象群組合對象的使用具有一緻性
透明方式 也就是說在Component中聲明所有用來管理子對象的方法 其中包括Add Remove等 這樣實作Component接口的所有子類都具備了Add Remove 這樣做的好處就是葉節點和枝節點對于外界沒有差別 它們具備完全一緻的行為接口 但問題也很明顯 因為葉節點類本身不具備Add() Remove()方法的功能 是以實作它是沒有意義的
安全方式 也就是在Component接口中不去聲明Add和Remove方法 那麼子類的葉節點也就不需要去實作它 而是在枝節點聲明所有用來管理子類對象的方法 不過由于不夠透明 是以樹葉和樹枝類将不具有相同的接口 用戶端的調用需要做相應的判斷 帶來了不便
當你發現需求中是展現部分與整體層次的結構時 以及你希望使用者可以忽略組合對象與單個對象的不同 統一地使用組合結構中的所有對象時 就應該考慮用組合模式了
組合模式定義了包含人力資源部和财務部這些基本對象和分公司等組合對象的類層次結構 基本對象可以被組合成更複雜的組合對象 而這個組合對象又可以被組合 這樣不斷地遞歸下去 客戶代碼中 任何用到基本對象的地方都可以使用組合對象了 使用者是不用關系到底是處理一個葉節點還是處理一個組合元件 也就用不着為定義組合而寫一些選擇判斷語句了 組合模式讓客戶可以一緻地使用組合結構和單個對象