设计模式 - 组合模式详解

基本介绍

一、组合模式(Composite Pattern)又叫部分总体模式,他建立了对象组的树形结构,将对象组合成树状结构以表示「总体 - 部分」的层次关系。java

二、组合模式使得用户对单个对象和组合对象的访问具备一致性,即:组合能让客户以一致的方式处理个别对象以及组合对象git

模式结构

Component(抽象构件):定义参加组合对象的公有方法和属性,能够定义一些默认的行为和属性。github

Composite(容器构件):树枝对象,它的做用是组合树枝结点和叶子结点造成一个树形结构。安全

Leaf(叶子构件):叶子构件的下面没有其余分支,也就是遍历的最小单位。ide


组合模式有两种实现:安全模式和透明模式,其结构以下图所示测试

  • 安全组合模式:在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在容器构件 Composite 类中声明并实现这些方法。
  • 透明组合模式:抽象构建角色中声明了全部用于管理成员对象的方法,对其它构件公开透明。

简单案例

要求:在页面展现出公司的部门组成(一个公司有多个部门,每一个部门有多个小组);this

这是一种很明显的树形结构,所以能够用组合模式解决code

「抽象构件」:OrganizationComponentcomponent

public abstract class OrganizationComponent {
    private String name;

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

    protected void add(OrganizationComponent component) {
        throw new UnsupportedOperationException("不支持添加操做");
    }

    protected void remove(OrganizationComponent component) {
        throw new UnsupportedOperationException("不支持删除操做");
    }

    protected abstract void print();


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

「容器构件」:Company、Department对象

public class Company extends OrganizationComponent {
    private List<OrganizationComponent> components = new ArrayList<>();

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

    @Override
    protected void add(OrganizationComponent component) {
        components.add(component);
    }

    @Override
    protected void remove(OrganizationComponent component) {
        components.remove(component);
    }

    @Override
    protected void print() {
        System.out.println("======="+getName()+"=======");
        for (OrganizationComponent component : components) {
            component.print();
        }
    }

    @Override
    public String getName() {
        return super.getName();
    }
}
public class Department extends OrganizationComponent {
    private List<OrganizationComponent> components = new ArrayList<>();

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

    @Override
    protected void add(OrganizationComponent component) {
        components.add(component);
    }

    @Override
    protected void remove(OrganizationComponent component) {
        components.remove(component);
    }

    @Override
    protected void print() {
        System.out.println("======="+getName()+"=======");
        for (OrganizationComponent component : components) {
            component.print();
        }
    }

    @Override
    public String getName() {
        return super.getName();
    }
}

「叶子构件」:Group,叶子构件不没有子节点了,因此不须要添加、删除之类的方法

public class Group extends OrganizationComponent {
    public Group(String name) {
        super(name);
    }

    @Override
    protected void print() {
        System.out.println(getName());
    }

    @Override
    public String getName() {
        return super.getName();
    }
}

「测试类」:Client

public class Client {
    @Test
    public void test01(){
        OrganizationComponent company = new Company("阿里巴巴");

        OrganizationComponent department1 = new Department("市场部");
        OrganizationComponent department2 = new Department("技术部");

        OrganizationComponent group1 = new Group("市场一组");
        OrganizationComponent group2 = new Group("市场二组");
        OrganizationComponent group3 = new Group("技术一组");
        OrganizationComponent group4 = new Group("技术二组");

        //添加部门
        company.add(department1);
        company.add(department2);
        //添加小组
        department1.add(group1);
        department1.add(group2);
        department2.add(group3);
        department2.add(group4);

        //打印结果
        company.print();
    }
}

「运行结果」

=======阿里巴巴=======
=======市场部=======
市场一组
市场二组
=======技术部=======
技术一组
技术二组

在 HashMap 中的应用

在 Java(jdk 1.8为例) 的集合类 HashMap 中,抽象构件是 Map,容器构件是 HashMap,叶子构件是 Node

进入源码能够看见,在 Map 中定义了许多公共方法

HashMap 实现了 Map,并对一些方法重写,并且 HashMap 中有一个静态内部类 Node,它就充当了叶子构件的角色,Node 中去除了 put、putAll 等方法,下面也没有子结点了

使用:

@Test
public void test02(){
    Map<String, String> map = new HashMap<>();
    map.put("k1", "v1");
    map.put("k2", "v2");
    System.out.println(map);
}

当咱们 put 一个键值对的时候,在 HashMap 内部会调用 putVal 方法,将键值对封装为 Node。

总结

一、简化客户端操做。客户端只须要面对一致的对象而不用考虑总体部分或者节点叶子的问题。

二、具备较强的扩展性。当咱们要更改组合对象时,咱们只须要调整内部的层次关系,客户端不用作出任何改动。

三、方便建立出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点或者叶子从而建立出复杂的树形结构。

四、须要遍历组织机构,或者处理的对象具备树形结构时,很是适合使用组合模式。

五、要求较高的抽象性。若是节点和叶子有不少差别性的话,好比不少方法和属性都不同,不适合使用组合模式。


p.s. 全部代码和笔记都可在 个人GitHub 中获取,若是对您有帮助的话,能够点个 star 支持一下 🙈

相关文章
相关标签/搜索