组合模式(Composite Pattern)-(最通俗易懂的案例)

定义

组合模式(Composite Pattern)属于结构型模式,将对象组合成树形结构以表示“部分”—“整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

什么叫“部分”—“整体”的层次结构呢,举个例子:
假如我们在网上购物买了很多的东西,仓库收到订单后按照订单明细给我们的东西打包,由于东西很多他们用了很多的包装盒,并最终用一个巨大的盒子来包裹每一个订单的商品,如下图所示:
在这里插入图片描述
每一个盒子里面都可能包含许多的小盒子和商品,以此类推。因此“部分”—“整体”是一个相对的概念,假如在第三层的包装盒内部还有许多的小盒子和商品,那么这个第三层的包装盒对于整个订单的包裹来说他是“部分”,而对于他里面的盒子与商品来说,他又是“整体”。

再比如我们电脑中的文件夹里面,A文件夹里面包含了B、C、D文件夹以及一个demo.txt文件,B文件夹里面又包括了E、F文件夹和demo.ps和demo.word文件。这也是“部分”—“整体”的层次结构。

结构图

Composite Pattern
解析:

  • component :一个接口或抽象类,描述了树中简单项目和复杂项目所共有的操作。
  • leaf:叶节点是树的基本结构, 它不包含子项目。一般情况下, 叶节点最终会完成大部分的实际工作, 因为它们无法将工作指派给其他部分。
  • composite:是包含叶节点或其他容器等子项目的单位。 容器接收到请求后会将工作分配给自己的子项目, 处理中间结果, 然后将最终结果返回给客户端。

实例

现在,假设我们要建立一个公司的销售部门层次结构。我们先把这个层次结构画一下:
在这里插入图片描述
然手直接上代码:
我们先建一个部门的接口Department:

package com.design_pattern.composite;

/**
 * Created on 2020/3/20
 * Package com.design_pattern.composite
 *
 * @author dsy
 */
public interface Department {
    void printDepartmentName();     //输出部门名称的方法
}

然后建立一个总的销售部门:SaleDepartment

package com.design_pattern.composite;

import java.util.ArrayList;
import java.util.List;

/**
 * Created on 2020/3/20
 * Package com.design_pattern.composite
 *
 * @author dsy
 */
public class SaleDepartment implements Department {

	//部门名称
    private  String name;  

	//相当于一个Composite,下面可以拥有其他的子部门,而不是一个叶子节点
    List<Department> departments = new ArrayList<>();  

	//用于增加子部门
    public void addDepartment(Department department){    
        departments.add(department);
    }

	//删除子部门
    public void remove(Department department){     
        departments.remove(department);
    }

    @Override
    public void printDepartmentName() {
    	//打印本部门的名称
        System.out.println(name);
        //打印本部门下的子部门的名称
        for (Department department:departments){
            department.printDepartmentName();
        }
    }

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

    public String getName() {
        return name;
    }

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

创建一个国内销售部门:DomesticSaleDepartment

package com.design_pattern.composite;

import java.util.ArrayList;
import java.util.List;

/**
 * Created on 2020/3/20
 * Package com.design_pattern.composite
 *
 * @author dsy
 */
public class DomesticSaleDepartment implements Department {

    private String name;

	//相当于一个Composite,下面可以拥有其他各个省份的子部门
    List<Department> list = new ArrayList<>();

    public DomesticSaleDepartment(String name) {
        this.name = name;
    }
	//用于增加子部门
    public void add(Department department){
        list.add(department);
    }
	//用于删除子部门
    public void remove(Department department){
        list.remove(department);
    }

    @Override
    public void printDepartmentName() {
        System.out.println(name);
        for (Department department:list){
            department.printDepartmentName();
        }
    }

    public String getName() {
        return name;
    }

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


建立一个国际销售部门:InternationalSaleDepartment ,我们假设国外业务不多,就不细分了,作为一个叶子节点

package com.design_pattern.composite;

/**
 * Created on 2020/3/20
 * Package com.design_pattern.composite
 *
 * @author dsy
 */
public class InternationalSaleDepartment implements Department {
    private String name;

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

    public String getName() {
        return name;
    }

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

	
    @Override
    public void printDepartmentName() {
        System.out.println(name);
    }
}

在建立一个浙江销售部门:ZheJiangSaleDepartment ,同样作为叶子节点

package com.design_pattern.composite;

/**
 * Created on 2020/3/20
 * Package com.design_pattern.composite
 *
 * @author dsy
 */
public class ZheJiangSaleDepartment implements Department {

    private String name;

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

    public String getName() {
        return name;
    }

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

    @Override
    public void printDepartmentName() {
        System.out.println(name);
    }
}

测试类:CompositeDemo

package com.design_pattern.composite;

/**
 * Created on 2020/3/20
 * Package com.design_pattern.composite
 *
 * @author dsy
 */
public class CompositeDemo {

    public static void main(String[] args) {
    	//创建一个总的销售部门作为根节点
        Department saleDepartment = new SaleDepartment("销售部门");
        //创建国内销售部门
        DomesticSaleDepartment domesticSaleDepartment = new DomesticSaleDepartment("国内销售部门");
        //创建国内浙江销售部门
        ZheJiangSaleDepartment ZheJiangSaleDepartment = new ZheJiangSaleDepartment("浙江销售部门");
        //将浙江销售部门加入到国内销售部门
        domesticSaleDepartment.list.add(ZheJiangSaleDepartment);
        //创建国际销售部门
        InternationalSaleDepartment internationalSaleDepartment = new InternationalSaleDepartment("国际销售部门");
        //将国内销售部门和国外销售部门全部加入到总的销售部门去
        ((SaleDepartment) saleDepartment).departments.add(domesticSaleDepartment);
        ((SaleDepartment) saleDepartment).departments.add(internationalSaleDepartment);
        //打印部门名称
        saleDepartment.printDepartmentName();
    }
}

打印输出:

销售部门
国内销售部门
浙江销售部门
国际销售部门

总结

使用场合
  • 需求中体现的是部分与整体层次的结构时,如实现树状结构,可以使用组合模式
  • 希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑用组合模式了
优点
  • 可以利用多态和递归机制更方便地使用复杂树结构
  • 符合开闭原则,无需更改现有代码,就可以在应用中添加新元素,使其成为对象树的一部分
缺点
  • 对于功能差异较大的类, 提供公共接口或许会有困难
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值