設計模式(八)組合模式 Composite

  • 組合模式:

  容許你將對象組合成樹形結構來表現「總體/部分」層次結構。組合能讓客戶以一致的方式處理個別對象以及對象組合。數據結構

 

  組合模式適用於建立複雜的對象,這個對象包含某些個別的對象以及這些對象的組合。app

  從操做的角度而言,客戶端對於 個別對象/組合 的操做是一致的。ide

 

  • 模擬場景

 

  如圖所示,總公司下屬有多個部門,而子公司能夠視爲多個部門的組合。ui

  整個數據結構呈樹狀,完美契合組合模式的應用場景。spa

 

  • UML:

  在這個場景中:code

  1. 個別對象 -> 人事部(HRDepartment)和財務部(FinanceDepartment)
  2. 個別對象的組合 -> 公司(Company)
  3. 不管是 Company 仍是 Department,對於 Client 而言,都被當作 CompanyItem 使用。
  4. 從樹形結構來理解,Department 是葉節點,Company 是非葉節點。

 

  • 代碼:
@Data
@AllArgsConstructor
@ToString
public abstract class CompanyItem {

    protected String name;

    protected void addCompanyItem(CompanyItem companyItem) {
        throw new UnsupportedOperationException("Not support to add companyItem");
    }

    protected void removeCompanyItem(CompanyItem companyItem) {
        throw new UnsupportedOperationException("Not support to remove companyItem");
    }

    protected abstract void lineOfDuty();

    protected abstract void showStructure(int depth);
}
public final class Company extends CompanyItem {

    private List<CompanyItem> childCompanyItems = new ArrayList<>();

    public Company(String name) {
        super(name);
    }

    @Override
    public void addCompanyItem(CompanyItem component) {
        childCompanyItems.add(component);
    }

    @Override
    public void removeCompanyItem(CompanyItem component) {
        childCompanyItems.remove(component);
    }

    @Override
    public void lineOfDuty() {
        childCompanyItems.forEach(companyItem -> companyItem.lineOfDuty());
    }

    @Override
    public void showStructure(int depth) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < depth; ++i) {
            builder.append("-");
        }
        System.out.println(builder.append(name));
        childCompanyItems.forEach(companyItem -> companyItem.showStructure(depth + 1));
    }
}
public final class FinanceDepartment extends CompanyItem {

    public FinanceDepartment(String name) {
        super(name);
    }

    @Override
    public void lineOfDuty() {
        System.out.println(name + ", treasurer is in charge of payroll");
    }

    @Override
    public void showStructure(int depth) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < depth; ++i) {
            builder.append("-");
        }
        System.out.println(builder.append(name));
    }
}
public final class HRDepartment extends CompanyItem {

    public HRDepartment(String name) {
        super(name);
    }

    @Override
    public void lineOfDuty() {
        System.out.println(name + ", HR is responsible for recruiting new employees");
    }

    @Override
    public void showStructure(int depth) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < depth; ++i) {
            builder.append("-");
        }
        System.out.println(builder.append(name));
    }
}

 

  • 客戶端調用:
    private CompanyItem createParentCompany() {
        CompanyItem parentCompany = new Company("Shanghai parent company");
        parentCompany.addCompanyItem(new HRDepartment("Parent company HR department"));
        CompanyItem southChildCompany = new Company("South child company");
        southChildCompany.addCompanyItem(new HRDepartment("South child company HR department"));
        parentCompany.addCompanyItem(southChildCompany);
        CompanyItem hongKongOffice = new Company("HongKong office");
        hongKongOffice.addCompanyItem(new FinanceDepartment("Hongkong office Finance department"));
        southChildCompany.addCompanyItem(hongKongOffice);
        parentCompany.addCompanyItem(new FinanceDepartment("Parent company Finance department"));
        return parentCompany;
    }

    @Test
    void testComposite() {
        CompanyItem parentCompany = createParentCompany();
        parentCompany.showStructure(1);
        System.out.println("===========================");
        parentCompany.lineOfDuty();
    }

 

  • 輸出:

相關文章
相關標籤/搜索