Java版设计模式之【组合模式】

179 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

概述

组合模式,结构型设计模式的一种,你可以将对象组合成树形层次结构,适得用户对单个对象和组合对象的使用具有一致性。

角色

抽象组件:定义了组合对象的共有方法和属性。

叶子节点:不包含子对象,没有其它的分支,是最终完成大部分实际业务逻辑的存在。

树枝节点:又称组合节点,是包含叶节点或其树枝节点的对象。它的左右是将树枝和叶子组合成一个树形结构,在接收到请求后会将工作分配给自己的子项目进行处理并将最终结果返回给客户端。

模板

抽象组件:获取当前节点信息。

public interface Company {
    /**
     * 获取信息
     */
    public String getInfo();
}

叶子节点:定义员工类,实现公司接口,展示当前对象的详细信息。

public class Employee implements Company{
    /**
     * 姓名
     */
    private String name;
    /**
     * 职位
     */
    private String position;
    /**
     * 薪水
     */
    private int salary;

    public Employee(String name, String position, int salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
    }

    @Override
    public String getInfo(){
        String info = "名称:" + this.name + "\t职位:" + this.position + "\t薪水" + this.salary;
        return info;
    }
}

树枝节点:定义具体公司类,实现公司接口,展示当前对象的详细信息,同时保存其它树枝节点或叶子节点。

public class ConcreteCompany implements Company{
    private ArrayList<Company> companies = new ArrayList<>();
    /**
     * 姓名
     */
    private String name;
    /**
     * 职位
     */
    private String position;
    /**
     * 薪水
     */
    private int salary;

    public ConcreteCompany(String name, String position, int salary) {
        this.name = name;
        this.position = position;
        this.salary = salary;
    }

    public void add(Company company){
        this.companies.add(company);
    }

    public void remove(Company company) {
        this.companies.remove(company);
    }

    public ArrayList<Company> getChild(){
        return this.companies;
    }

    @Override
    public String getInfo(){
        String info = "名称:" + this.name + "\t职位:" + this.position + "\t薪水" + this.salary;
        return info;
    }
}

客户端:创建公司树,添加各级部门与员工,通过递归展示关联信息。

public class CompositePattern {
    public static void main(String[] args) {
        // 主节点
        ConcreteCompany root = new ConcreteCompany("张三", "CEO", 100000);
        ConcreteCompany developDep = new ConcreteCompany("李四", "研发部经理", 12000);
        ConcreteCompany salesDep = new ConcreteCompany("王五", "销售部经理", 15000);
        ConcreteCompany financeDep = new ConcreteCompany("马六", "财务部经理", 10000);

        // 子节点
        Employee e1 = new Employee("A", "研发部", 3000);
        Employee e2 = new Employee("B", "研发部", 2500);
        Employee e3 = new Employee("C", "研发部", 4000);
        Employee e4 = new Employee("D", "研发部", 6000);
        Employee e5 = new Employee("E", "销售部", 3500);
        Employee e6 = new Employee("F", "销售部", 2300);
        Employee e7 = new Employee("G", "销售部", 5000);
        Employee e8 = new Employee("H", "财务部", 3800);
        Employee e9 = new Employee("I", "财务部", 4300);

        // 生成树
        root.add(developDep);
        root.add(salesDep);
        root.add(financeDep);
        developDep.add(e1);
        developDep.add(e2);
        developDep.add(e3);
        developDep.add(e4);
        salesDep.add(e5);
        salesDep.add(e6);
        salesDep.add(e7);
        financeDep.add(e8);
        financeDep.add(e9);

        // 显示层次
        System.out.println(root.getInfo());
        display(root);
    }

    /**
     * 递归遍历
     */
    private static void display(ConcreteCompany root) {
        for (Company company : root.getChild()) {
            if (company instanceof Employee){
                // 子节点
                System.out.println(company.getInfo());
            }else{
                // 父节点
                System.out.println("\n" + company.getInfo());
                display((ConcreteCompany)company);
            }
        }
    }
}

小结

优点

开闭原则:节点自由增加,无需更改现有代码,可以在应用中添加新元素使其成为对象树的一部分。

调用简单:可以利用多态和递归机制来使用该树结构,对于调用者来说,局部和整体并没有区别

缺点

不易控制:对于功能差异较大的类,提供公共接口比较困难,在特定情况下,过度一般化组件接口会使其变得令人难以理解。

不易继承:不方便使用继承的方式来增加新的行为。

适用场景

  • 需要实现树状对象结构,例如树形菜单、文件和文件夹管理等可以使用组合模式
  • 客户端希望以同一个接口处理单个组件或组合组件时可以使用组合模式

最后

文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!!!

如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!