今天是:
带着程序的旅程,每一行代码都是你前进的一步,每个错误都是你成长的机会,最终,你将抵达你的目的地。
title

组合设计模式(Composite)

定义

组合模式(Composite Pattern)是一种结构性设计模式,它允许你将对象组合成树形结构,以表示"部分-整体"层次结构。这个模式允许客户端统一地对待单个对象和组合对象。

意图

  • 将对象组织成树形结构:组合模式允许将对象组织成层次结构,其中单个对象和组合对象都被视为相同类型的组件。

  • 客户端统一访问:客户端可以统一地访问单个对象和组合对象,不需要区分它们的具体类型,因为它们都实现了相同的接口。

  • 简化客户端代码:组合模式简化了客户端代码,因为客户端不需要处理对象的类型,而只需调用通用的接口方法。

  • 支持递归结构:组合模式支持递归结构,因此可以方便地处理深层次的组合对象。

  • 增加新类型的组件:组合模式使得增加新类型的组件变得相对容易,因为只需要实现通用的接口。

参与者(角色)

  • 组件(Component):这是一个抽象类或接口,它定义了组合对象和单个对象的通用接口。所有具体组件类都必须实现这个接口,它包括方法如显示名称、添加子组件、移除子组件等。

  • 叶子(Leaf):这是组合模式中的单个对象,它实现了组件接口。叶子对象没有子组件,通常表示了树结构中的最小单元。

  • 组合(Composite):这是组合模式中的组合对象,它实现了组件接口。组合对象可以包含其他组件,包括叶子对象和其他组合对象,形成一个树形结构。

举例

以下是某公司的组织机构实现的组合模式

类图:

这个例子中对应类的角色如下:

  • Component(组件):抽象的接口或类,定义了单个对象和组合对象的通用方法。在示例中,Component 接口定义了 showName() 方法,表示显示对象的名称。

  • Company(公司):具体的组合对象,实现了 Component 接口。Company 类表示公司,可以包含其他组件,包括子公司和部门。它负责管理子组件的添加和删除。

  • SubsidiaryCompany(子公司):具体的组合对象,也实现了 Component 接口。SubsidiaryCompany 类表示子公司,可以包含其他组件,包括部门。它同样负责管理子组件的添加和删除。

  • Department(部门):叶子对象,实现了 Component 接口。Department 类表示部门,它是组织结构的最小单元,没有子组件。

组织抽象接口

public interface Organization {
    void showName();
}

 

公司类

@Slf4j
public class Company implements Organization{
    private String name;
    private List<Organization> children = new ArrayList<>();

    public Company(String name) {
        this.name = name;
    }

    public void add(Organization component) {
        children.add(component);
    }

    public void remove(Organization component) {
        children.remove(component);
    }

    @Override
    public void showName() {
        log.info("公司名字: " + name);
        for (Organization component : children) {
            component.showName();
        }
    }
}  }
}

 

子公司

@Slf4j
public class SubsidiaryCompany implements Organization{
    private String name;
    private List<Organization> children = new ArrayList<>();

    public SubsidiaryCompany(String name) {
        this.name = name;
    }

    public void add(Organization component) {
        children.add(component);
    }

    public void remove(Organization component) {
        children.remove(component);
    }

    @Override
    public void showName() {
        log.info("子公司: " + name);
        for (Organization component : children) {
            component.showName();
        }
    }
}

 

部门

@Slf4j
public class Department implements Organization{
    private String name;

    public Department(String name) {
        this.name = name;
    }

    @Override
    public void showName() {
        log.info("部门名称: " + name);
    }
}

 

测试,组合一个组织机构

public class App {
    public static void main(String[] args) {
        Company parentCompany = new Company("科技公司");

        SubsidiaryCompany subsidiary1 = new SubsidiaryCompany("北京分公司");
        Department hrDepartment = new Department("北京Hr部门");
        Department devDepartment = new Department("北京研发部门");
        subsidiary1.add(hrDepartment);
        subsidiary1.add(devDepartment);

        SubsidiaryCompany subsidiary2 = new SubsidiaryCompany("广州分公司");
        Department finaceDepartment = new Department("广州财务部门");
        Department saleDepartment = new Department("广州销售部门");
        subsidiary2.add(finaceDepartment);
        subsidiary2.add(saleDepartment);

        parentCompany.add(subsidiary1);
        parentCompany.add(subsidiary2);

        parentCompany.showName();
    }
}

 

优点

  1. 统一接口:组合模式允许客户端统一地对待单个对象和组合对象,因为它们都实现了相同的接口,从而简化了客户端代码。

  2. 灵活性:组合模式支持递归结构,可以方便地处理深层次的组合对象。你可以轻松地构建具有多层次结构的对象。

  3. 可扩展性:向组合结构中添加新类型的组件相对容易,因为只需要实现通用的接口即可,不需要修改现有代码。

  4. 可维护性:组合模式使代码更加清晰,因为它减少了与特定对象类型的耦合,使代码更易于维护和扩展。

缺点

  1. 复杂性:组合模式可能会引入额外的复杂性,因为它创建了一个对象层次结构。这可能会使代码难以理解和调试。

  2. 性能开销:递归遍历组合结构可能会导致性能开销,特别是当结构非常深或包含大量组件时。

  3. 限制操作:组合模式通常不支持在组合对象中添加或删除子对象的操作,因为这些操作可能会破坏整体结构。

  4. 过度一般化:在某些情况下,组合模式可能会过于一般化,不适用于所有类型的对象组织结构。

组合模式的应用

Hashmap中的组合模式

Map接口对应Component

HashMap对应Composite

Node对应叶子

 

分享到:

专栏

类型标签

网站访问总量