20. 组合模式

定义

组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。

通俗理解

生活中有许多树型结构的东西,例如一家公司的员工关系,由董事长管理CEO、COO、CTO、CFO等等,又由CTO管理研发部门,测试部门,运维部门等等,每一个部门也有部门老大,部门当中也有项目组,项目组中有组长,组长还管理着组员;文件夹的目录也是这样的一个结构,文件夹中有文件夹,也有文件,他们按照树型的结构一直往下延伸。

就用员工组织做例子。按一般的想法设计这一个树形的系统,我们会认为,部门是一个是一个对象,而员工是另外一个对象。对于部门而言,我们能够显示他的基本信息,能够添加部门(子部门)、添加部门(子部门)、添加员工、删除员工,而对于个人而言,我们只能够显示基本信息,对于添加员工和删除员工的操作是不存在的。

把他们割裂开来会出现什么问题?第一:访问部门和访问个人需要区分两个不同的接口,而显示基本信息的是部门和个人都通用的方法却没有提供出来。第二:造成部门会很复杂,在部门当中,需要写添加部门的方法,同时也需要写添加员工的方法;第三:不方便扩展,如果我部门是具有不同的性质的,例如在信息部门中添加研发部门,运维部门等,研发和运维有不同的性质,那么我们需要在信息部门当中改相关的方法,这就违背了开闭原则。

换一个想法,把个人和部门都看成是一个一样的东西,部门和个人都有显示信息的方法,那么我们就把他们提取出来,做成公用的方法。而关于添加个人的方法,由于个人不可能再添加了,所以当用户调用这个方法的时候,就抛出异常。这样的设计,就能够整体对待部门和个人了。

示例

渣渣程序

员工信息

public class Staff {
    private String name;
    public Staff(String name) {
        this.name = name;
    }
    public void info() {
        System.out.println(name);
    }
}

部门

public class Department {
    public String name;
    public List<Staff> staffList = new ArrayList<>();
    public List<Department> departmentList = new ArrayList<>();
    public Department(String name) {
        this.name = name;
    }
    public void addStaff(Staff staff) {
        staffList.add(staff);
    }
    public void removeStaff(Staff staff) {
        staffList.remove(staff);
    }
    public void addDepartment(Department department) {
        departmentList.add(department);
    }
    public void removeDepartment(Department department) {
        departmentList.remove(department);
    }
    public void info() {
        System.out.println(name);
    }
}

入口

public class Main {
    public static void main(String[] args) {
        Department infoDep = new Department("信息部门");
        Department devDep = new Department("研发部门");
        Department opsDep = new Department("运维部门");
        infoDep.addDepartment(devDep);
        infoDep.addDepartment(opsDep);
        Staff ccc = new Staff("ccc");
        Staff ddd = new Staff("ddd");
        devDep.addStaff(ccc);
        devDep.addStaff(ddd);
        Staff eee = new Staff("eee");
        Staff fff = new Staff("fff");
        opsDep.addStaff(eee);
        opsDep.addStaff(fff);
        new Main().info(infoDep);
    }
    public void info(Department department) {
        department.info();
        for (Staff staff : department.staffList) {
            staff.info();
        }
        for(Department department1 : department.departmentList) {
            info(department1);
        }
    }
}
/**
* 信息部门
* 研发部门
* ccc
* ddd
* 运维部门
* eee
* fff
*/

优化

类图

程序

部门和员工的统一抽象类

public abstract class DepartmentStaff {
    public abstract void info();
    public boolean isDepartment() {
        return false;
    }
    public void add(DepartmentStaff departmentStaff) {
        System.out.println("系统发生错误");
    }
    public void remove(DepartmentStaff departmentStaff) {
        System.out.println("系统发生错误");
    }
    public List<DepartmentStaff> getChild() {
        System.out.println("系统发生错误");
        return null;
    }
}

部门

public class Department extends DepartmentStaff {
    private List<DepartmentStaff> children;
    private String name;

    public Department(String name) {
        this.name = name;
        children = new ArrayList<>();
    }

    @Override
    public void info() {
        System.out.println("部门:"+name);
        for(DepartmentStaff departmentStaff : getChild()) {
            departmentStaff.info();
        }
    }

    @Override
    public void add(DepartmentStaff departmentStaff) {
        getChild().add(departmentStaff);
    }

    @Override
    public void remove(DepartmentStaff departmentStaff) {
        getChild().remove(departmentStaff);
    }

    @Override
    public List<DepartmentStaff> getChild() {
        return children;
    }

    public void setChildren(List<DepartmentStaff> children) {
        this.children = children;
    }
}

员工

public class Staff extends DepartmentStaff {
    private String name;

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

    @Override
    public void info() {
        System.out.println("员工:"+name);
    }
}

入口

public class Main {
    public static void main(String[] args) {
        DepartmentStaff d1 = new Department("d1");
        DepartmentStaff d1_1 = new Department("d1_1");

        DepartmentStaff s1 = new Staff("s1");
        d1_1.add(s1);
        d1.add(d1_1);
        d1.info();
    }
}
//部门:d1
//部门:d1_1
//员工:s1

优点

  1. 整体和部分都是一样的,调用方不用关心处理的是整体还是部分;
  2. 节点层次容易添加。

缺点

  1. 直接使用了实现,违反依赖倒置原则。

应用场景

  1. 整体和部分希望一致对待的;
  2. 维护整体与部分的关系的;

程序

e20_composite_pattern|给我star

吐槽

一脸懵逼

https://www.jianshu.com/p/af20a0fff472

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,701评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,649评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,037评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,994评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,018评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,796评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,481评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,370评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,868评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,014评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,153评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,832评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,494评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,039评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,437评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,131评论 2 356

推荐阅读更多精彩内容

  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,940评论 2 89
  • 旅游能带给人,丰富自己的阅历,让人更加包容。感受不同风情,开放自己的眼界。
    斐丽希娅阅读 112评论 0 0
  • “为什么要叫黑色星期五” 让我百度一下啊,原来是这样啊,难怪这几天他总是说感恩节后很多人去超市买东西,当时没想明白...
    Jerryboy阅读 98评论 0 1
  • 考虑好好减个肥吧~做个棒棒的女子~棒棒的自己~遇到棒棒的人~ 晚上12点一定要睡觉! 一定要注意眼睛 一定要注意嗓...
    我要小马甲阅读 172评论 0 0
  • 马恩列、毛邓三 科学发展观 牢记在心间 新时期、新思想 航行舵手重呼呼 和谐价值新体系 爱国敬业要牢记 文明和谐与...
    求索的路阅读 192评论 0 0