zoukankan      html  css  js  c++  java
  • 组合模式

    2019年5月23日21:50:31

    组合模式(composite pattern)

    定义

    组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。————《设计模式:可复用面向对象软件的基础》

    组合模式是一个结构型模式。

    使用场景

    当你发现需求中是用树形结构体现部分与整体层次关系的结构时,且你希望用户可以忽略整体和部分、组合对象和单个对象的不同,统一地使用组合结构中的所有对象时,就应该使用组合模式。

    组合模式解决上面所说的两个问题:

    1、部分与整体的层次关系表示为树形结构、

    2、部分与整体的对象,是能让客户端能统一对待、不需区分的对象。

    场景:树形菜单,文件、文件夹的管理。

    角色

    抽象组件角色(Component):

    • 所有组件的抽象
    • 声明在组合模式中的对象的接口

    叶子角色(Leaf):

    • 表示组合模式中的叶子对象
    • 实现了Component
    • 没有子节点

    组合角色(Composite):

    • 表示一个组合组件(拥有叶子节点)
    • 实现了Component,
    • 拥有子节点,并具备操作Component的方法,增加组件、删除组件等

    图示

    组合模式结构图:

    组合模式结构图

    代码示例

    深圳某公司总部使用的OA系统,由于简单易用,反响良好的原因,准备被推广到各分公司使用。

    关于组织结构的设计,原来是这样的:一个公司总部下面有人力资源部、财务部等。组织结构图如下:

    推广之前的组织结构图

    类图如下:

    应用组合模式前的组合结构类图

    代码如下:

    // 组织
    public interface Organization {
        void addOrg(Department department);
        void removeOrg(Department department);
        String getName();
        void showOrg();
        void displayDuty();
    }
    // 公司总部
    public class Headquarters implements  Organization {
        private List<Department> departments = new ArrayList<>();
    
        @Override
        public void addOrg(Department department) {
            departments.add(department);
        }
    
        @Override
        public void removeOrg(Department department) {
            departments.remove(department);
        }
    
        public String getName() {
            return this.getClass().getSimpleName();
        }
    
        @Override
        public void showOrg() {
            System.out.println("-" + getName());
            for (Department department : departments) {
                System.out.println("--" +  department.getName());
            }
        }
    
        @Override
        public void displayDuty() {
            for(Department department : departments) {
                department.duty();
            }
        }
    }
    // 部门
    public interface Department {
        String getName();
        void duty();
    }
    // 财务部
    public class FinanceDepartment implements Department {
    
        @Override
        public String getName() {
            return this.getClass().getSimpleName();
        }
    
        @Override
        public void duty() {
            System.out.println("财务部负责公司财务收支管理");
        }
    }
    // 人力资源部
    public class HumanResourceDepartment implements Department{
    
        @Override
        public String getName() {
            return this.getClass().getSimpleName();
        }
    
        @Override
        public void duty() {
            System.out.println("人力资源部负责员工招聘培训管理");
        }
    }
    // 测试类
    public class Before {
        public static void main(String[] args) {
            Organization hq = new Headquarters();
    
            Department fnc = new FinanceDepartment();
    
            Department hr = new HumanResourceDepartment();
    
            hq.addOrg(fnc);
            hq.addOrg(hr);
    
            System.out.println("====组织结构====");
            hq.showOrg();
            System.out.println("====部门职责====");
            hq.displayDuty();
        }
    }
    

    测试结果:

    应用组合模式之前的测试结果

    组织结构需求现在变成了:总部下面不仅是只有部门,还会有分公司。之前的设计明显是不可以用了,接口Organization中addOrg、removeOrg方法都是面对于Department的。现在需要不区分部门、分公司和总部,且组织结构是用树形结构来体现层次关系的。组合模式就派上用场了。

    推广之后组织机构图:

    推广之后的组织机构图

    应用组合模式的类图:

    应用组合模式的类图

    应用组合模式的代码:

    // 公司组织或部门
    public interface Company {
    
        void addOrg(Company company);
        void removeOrg(Company company);
        void showOrg(int depth);
        default void print(int dept) {
            while(dept-- > 0) {
                System.out.print("-");
            }
        }
    }
    // 总部或分公司
    public class ConcreteComp implements Company {
        private String name = "";
        private List<Company> companies = new ArrayList<>();
        ConcreteComp(String name) {
            this.name = name;
        }
    
        @Override
        public void addOrg(Company company) {
            companies.add(company);
        }
    
        @Override
        public void removeOrg(Company company) {
            companies.remove(company);
        }
    
        @Override
        public void showOrg(int dept) {
            print(dept);
            System.out.println(this.name);
            for (Company c : companies) {
                c.showOrg(dept + 2);
            }
        }
    }
    // 财务部
    public class FinanceDepartment implements Company {
        private String name = "";
        FinanceDepartment(String name) {
            this.name = name;
        }
    
        @Override
        public void addOrg(Company company) {
        }
    
        @Override
        public void removeOrg(Company company) {
        }
    
        @Override
        public void showOrg(int dept) {
            print(dept);
            System.out.println(this.name);
        }
    }
    // 人力资源部
    public class HumanResourceDepartment implements Company {
        private String name = "";
        HumanResourceDepartment(String name) {
            this.name = name;
        }
    
        @Override
        public void addOrg(Company company) {
        }
    
        @Override
        public void removeOrg(Company company) {
        }
    
        @Override
        public void showOrg(int dept) {
            print(dept);
            System.out.println(this.name);
        }
    }
    // 测试类
    public class After {
        public static void main(String[] args) {
            Company headquarters = new ConcreteComp("公司总部");
            headquarters.addOrg(new FinanceDepartment("财务部"));
            headquarters.addOrg(new HumanResourceDepartment("人力资源部"));
    
            Company gd = new ConcreteComp("广东分公司");
            gd.addOrg(new FinanceDepartment("财务部"));
            gd.addOrg(new HumanResourceDepartment("人力资源部"));
    
            Company sz = new ConcreteComp("深圳分公司");
            sz.addOrg(new FinanceDepartment("财务部"));
            sz.addOrg(new HumanResourceDepartment("人力资源部"));
    
            gd.addOrg(sz);
    
            Company sh = new ConcreteComp("上海分公司");
            sh.addOrg(new FinanceDepartment("财务部"));
            sh.addOrg(new HumanResourceDepartment("人力资源部"));
    
            headquarters.addOrg(gd);
            headquarters.addOrg(sh);
    
            headquarters.showOrg(1);
    
            Company test = new FinanceDepartment("测试财务部");
            test.addOrg(new HumanResourceDepartment("测试人力资源部"));
            test.addOrg(sh);
    
            test.showOrg(1);
        }
    }
    

    测试结果:

    应用组合模式之后的测试结果

    总部下可以添加分公司和部门,分公司下也可以添加分公司和部门,甚至部门下也可以添加分公司和部门,做到了不用区分整体和部分。只是部门下添加分公司和部门是不起作用的。

    透明方式与安全方式

    上面应用组合模式的方式就是透明方式,接口Company定义了addOrg、removeOrg方法,无论是叶子角色还是树枝角色都拥有addOrg、removeOrg方法,从实际使用的角度来说,叶子角色不需要这两个方法。对于外界来说,叶子和树枝的区别是透明的,这就是透明方式。

    安全方式就是接口Company里没有定义addOrg、removeOrg方法,只在树枝角色添加addOrg、removeOrg方法。这样用户需要对叶子角色和树枝角色进行判断能不能使用ddOrg、removeOrg方法。

    透明方式的缺点是叶子角色在添加叶子或者树枝时是什么也不做,用户觉得应该是操作成功了,但是并没有操作成功。安全方式的缺点就是在添加叶子和树枝的时候需要进行判断。

    优点

    对服务端来说,以树形结构清晰定义了整体和部分的层次关系,只需要知道自己的父节点就可以自由添加子节点。

    对客户端来说,可以忽略整体和部分的差异,不需关心是单个对象还是组合对象,简化了逻辑。

    总结

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

    参考

    《大话设计模式》

    2019年7月18日20:09:21

  • 相关阅读:
    idea创建maven web项目需要注意的一些细节
    idea中默认maven配置
    怎么写开发用例?
    css样式 给div水平垂直居中
    elementUI日期选择器里禁用选择未来时间
    常用的正则表达式
    Unknown custom element: <el-table-column>
    几个简单的JavaScript字符串方法
    新的vue-cli默认禁止了commonjs语法,可以添加babel解决
    解决webstorm左下角没有vue的npm项目启动快捷方式
  • 原文地址:https://www.cnblogs.com/mingmingcome/p/11215497.html
Copyright © 2011-2022 走看看