『设计模式』结构型 ——组合模式

在现实生活中,存在很多“部分-整体”的关系,例如,大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣服与衣柜、以及厨房中的锅碗瓢盆等。在软件开发中也是这样,例如,文件系统中的文件与文件夹、窗体程序中的简单控件与容器控件等。对这些简单对象与复合对象的处理,如果用组合模式来实现会很方便。

定义

组合模式,将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

在这里插入图片描述

组合模式中的角色:

  • Component 抽象组件:为组合中所有对象提供一个接口,不管是叶子对象还是组合对象。
  • Composite 组合节点对象:实现了 Component 的所有操作,并且持有子结点对象。
  • Leaf 叶结点对象:叶结点对象没有任何子结点,实现了 Component 中的某些操作。

组合模式的主要优点有:

  1. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码
  2. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”

其主要缺点是:

  1. 设计较复杂,客户端需要花更多时间理清类之间的层次关系
  2. 不容易限制容器中的构件
  3. 不容易用继承的方法来增加构件的新功能

组合模式的结构与实现

组合模式分为透明式的组合模式和安全式的组合模式。

透明方式

在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 add()、remove() 及 getChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。

在这里插入图片描述

安全方式

在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。

在这里插入图片描述

使用场景

  1. 在需要表示一个对象整体与部分的层次结构的场合
  2. 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合

示例——公司管理系统

在这里插入图片描述

【公司类——抽象类或接口】

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(); // 履行职责
}

【具体公司类——实现接口、树枝节点】

public class ConcreteCompany extends Company {
    private final List<Company> children = new ArrayList<>();

    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) {
        super.display(depth);
        for (Company component : children) {
            component.display(depth + 2);
        }
    }

    @Override
    public void lineOfDuty() {
        for (Company component : children) {
            component.lineOfDuty();
        }
    }
}

【人力资源部】

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 lineOfDuty() {
        System.out.println(name + "员工招聘培训管理");
    }
}

【财务部】

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 lineOfDuty() {
        System.out.println(name + "公司财务收支管理");
    }
}

【测试类】

public class Test {
    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(1);

        System.out.println("\n职责:");
        root.lineOfDuty();
    }
}

输出结果:

结构图:
-北京总公司
---总公司人力资源部
---总公司财务部
---上海华东分公司
-----上海华东分公司人力资源部
-----上海华东分公司财务部
-----南京办事处
-------南京办事处人力资源部
-------南京办事处财务部
-----杭州办事处
-------杭州办事处人力资源部
-------杭州办事处财务部

职责:
总公司人力资源部员工招聘培训管理
总公司财务部公司财务收支管理
上海华东分公司人力资源部员工招聘培训管理
上海华东分公司财务部公司财务收支管理
南京办事处人力资源部员工招聘培训管理
南京办事处财务部公司财务收支管理
杭州办事处人力资源部员工招聘培训管理
杭州办事处财务部公司财务收支管理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值