其他分享
首页 > 其他分享> > 秒懂设计模式之组合模式(Composite Pattern)

秒懂设计模式之组合模式(Composite Pattern)

作者:互联网

[版权申明] 非商业目的注明出处可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/116378002
出自:shusheng007

设计模式汇总篇,一定要收藏:

永不磨灭的设计模式(有这一篇真够了,拒绝标题党)

文章目录

概述

组合模式出镜率不算特别高,但是一旦出境说明这个问题如果不使用它将变得非常困难。Android的View体系的设计方式就是组合模式非常经典的成功案例。

类型

结构型(structural)

难度

3颗星

定义

组合模式允许以相同的方式处理单个对象和对象的组合体

不理解不要紧,接着往下看

使用场景

UML类图

在这里插入图片描述

从上图可见组合模式共有3组成部分

抽象类,定义统一的处理操作。

叶子节点,即单个对象

组合对象,里面持有一个List<Component>

我们使用了组合模式中所谓的透明方式,因为我们将单个对象和组合对象按照完全一样的事物对待了,所以接口对外很透明。统一操作都是在Component中定义的,所有继承至它的节点都要实现,而有些操作叶子节点是不支持的,例如添加移除节点等,这样就要求叶子节点处理好这些方法。

实例

林蛋大最近比较烦,公司新接了个外包IT项目,甲方是传统行业的老板,总是感觉这么简单的功能为什么要那么多钱,关键还慢…这不,刚刚要求蛋大写一个"小软件"用来管理公司的组织架构…

蛋大本来还想沟通下需求:王老板,这个活可大可小,您是不是想要…巴拉巴拉。把王老板烦的啊:小林啊,你别说了,我给你3天时间你去先做一个我看看,不行就再改嘛…。蛋大在心中怒了:老子姓楚!名中天… 做你mlgb,需求不给我做你mlgb… 但最后还是陪着笑脸说那我试试吧…

蛋大找王二狗帮忙出了个设计方案,此案例使用组合模式可解

第一,设计一个个体与组合通用的接口

定义对外展示的统一处理接口

public abstract class OrganizationComponent {
    private String name;

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

    public String getName() {
        return name;
    }

    public abstract void add(OrganizationComponent organization);

    public abstract OrganizationComponent getChild(String orgName);

    public abstract int getStaffCount();

    @Override
    public String toString() {
        return name;
    }
}

第二,组合类

此类持有一个List<OrganizationComponent>,并继承OrganizationComponent

public class OrganizationComposite extends OrganizationComponent {

    //很关键,这体现了组合的思想
    private List<OrganizationComponent> organizations = new ArrayList<>();

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

    @Override
    public void add(OrganizationComponent organization) {
        organizations.add(organization);
    }

    @Override
    public OrganizationComponent getChild(String orgName) {
        for (OrganizationComponent org : organizations) {
            OrganizationComponent targetOrg = org.getChild(orgName);
            if (targetOrg != null) {
                return targetOrg;
            }
        }
        return null;
    }

    @Override
    public int getStaffCount() {
        int count = 0;
        for (OrganizationComponent organization : organizations) {
            count += organization.getStaffCount();
        }
        return count;
    }
}   

第三,叶子节点

叶子节点就是单个对象了,我们要使用合适的方式处理那些叶子节点不支持的对外接口方法。因为用户使的时候只会看到对外暴露的统一接口,他不知道此对象是叶子节点还是组合对象。

public class ItDepartment extends OrganizationComponent {

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

    @Override
    public int getStaffCount() {
        return 20;
    }

    @Override
    public void add(OrganizationComponent organization) {
        throw new UnsupportedOperationException(this.getName()+"已经是最基本部门,无法增加下属部门");
    }

    @Override
    public OrganizationComponent getChild(String orgName) {
        if(getName().equals(orgName)){
            return this;
        }
        return null;
    }
}
// 其他叶子节点类似
...

第四,客户端

我们来看看是否达到了我们的设计目的:以统一的接口操作单个对象与其组合对象。

首先构建一个组合对象。模拟构建一家公司,公司下设行政部门和IT部门,还有一个天津分公司,而天津分公司又下设一个行政部门和IT部门。

然后我确定查询这个公司任何部门的员工人数。我们可以看到在查询过程中,我们没有判断当前对象到底是什么部门对象,都是以统一的接口在操作。

public class CompositeClient {

    private OrganizationComponent constructOrganization() {
        //构建总部
        OrganizationComposite head = new OrganizationComposite("总公司");
        AdminDepartment headAdmin = new AdminDepartment("总公司行政部");
        ItDepartment headIt = new ItDepartment("总公司It部");
        head.add(headAdmin);
        head.add(headIt);

        //构建分公司
        OrganizationComposite branch1 = new OrganizationComposite("天津分公司");
        AdminDepartment branch1Admin = new AdminDepartment("天津分公司行政部");
        ItDepartment branch1It = new ItDepartment("天津分公司It部");
        branch1.add(branch1Admin);
        branch1.add(branch1It);

        //将分公司加入到head中
        head.add(branch1);

        return head;
    }

    public void listOrgInfo() {
        OrganizationComponent org = constructOrganization();
        System.out.println(String.format("%s共有%d名员工",
                org.getName(), org.getStaffCount()));

        OrganizationComponent subOrg = org.getChild("天津分公司行政部");
        System.out.println(String.format("%s共有%d名员工",
                subOrg.getName(), subOrg.getStaffCount()));
    }
}

输出:

总公司共有140名员工
天津分公司行政部共有50名员工

技术要点总结

透明方式将所有对外操作都放在Component,叶子节点也得提供这些接口,虽然它实际上不支持这些操作。而安全方式只将叶子节点与组合对象同时提供的操作放在Component

为啥叫透明方式呢?因为用户使用的时候根本不管是叶子节点,还是组合对象,反正看到的接口都一样。这样就不安全了,因为万一这个对象是个叶子节点,假设你又使用了一个它不能提供的操作,例如add,就出问题了…

优缺点

优点

缺点

总结

设计模式值得你可以练习!

最后,如果你从本文中有所收获,可否点赞转发支持一下博主,你小小的鼓励,是激发博主持续写作的动力…

GitHub源码地址design-patterns

标签:设计模式,String,组合,Composite,Pattern,节点,对象,OrganizationComponent,public
来源: https://blog.csdn.net/ShuSheng0007/article/details/116378002