聊聊Java设计模式-组合模式

简介: 组合(Composite)模式,又叫做树形模式,主要用来处理树形结构数据。是将一组对象组织成树形结构,以表示一种“部分-整体”的层次结构。让客户端可以统一单个对象和组合对象的处理逻辑

组合(Composite)模式,又叫做树形模式,主要用来处理树形结构数据。是将一组对象组织成树形结构,以表示一种“部分-整体”的层次结构。让客户端可以统一单个对象和组合对象的处理逻辑。

组织架构图

一、组合模式介绍

组合模式通过以树形结构来表示“部分-整体”,使得用户对叶对象和组合对象的使用具有一致性。也就是说在组合模式中,整个树形结构的对象都属于同一种类型,用户可以对叶对象和组合对象统一处理。

1.1 组合模式分类

组合模式主要有透明式和安全式两种分类,下面来分别说明

1.1.1 透明式组合模式

在该方式中,抽象构件声明了所有子类中的全部方法,这样实现抽象构件接口的所有子类都具备了全部方法,这样的好处是叶节点和枝节点对于外界没有任何区别,它们具备了完全一致的接口。但是对于叶节点有些本身不具备的方法,就可能会有安全隐患(空指针异常等)。其结构类图如下所示:

image-20220403141237169

  • Component:抽象构件,为叶节点和树枝节点声明公共接口,以及访问和管理子类的接口
  • Composite:树枝构件,组合中的分支节点对象,作用是存储和管理子部件
  • Leaf:树叶构件,组合中的叶节点对象,用于继承和实现抽象构件
  • Client:客户端

1.1.2 安全式组合模式

前面提到透明式组合模式中,因为抽象构件声明所有子类方法,有可能会造成安全问题。所以在安全式中,将管理叶节点的方法转移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了透明式组合模式中的安全问题。但是由于树叶和树枝构件有不同的接口,因此在使用时,就不能将两种构件一概而论,对于客户端调用方而言,就失去了透明性。其结构类图如下所示:

image-20220403141317008

  • Component:抽象构件,为叶节点和树枝节点声明公共接口,没有访问和管理子类的接口
  • Composite:树枝构件,组合中的分支节点对象,作用是存储和管理子部件
  • Leaf:树叶构件,组合中的叶节点对象,没有对子类的管理方法
  • Client:客户端

1.2 组合模式实现

根据上面的类图,可以实现如下代码:

1.2.1 透明式组合模式实现

/**
 * @description: 透明式抽象构件
 * @author: wjw
 * @date: 2022/4/3
 */
public interface Component {
   
   

    /**公共操作方法**/
   void operation();

    /**
     * 添加构件
     * @param c 组合模式中的构件
     */
    void add(Component c);

    /**
     * 移除构件
     * @param c 组合模式中的构件
     */
    void remove(Component c);

    /**
     * 获得子对象
     * @param t 子对象序号
     * @return  子对象
     */
    Component getChild(int t);

}

/**
 * @description: 树枝节点
 * @author: wjw
 * @date: 2022/4/3
 */
public class Composite implements Component{
   
   

    private ArrayList<Component> children = new ArrayList<>();

    @Override
    public void operation() {
   
   
        for (Component child : children) {
   
   
            child.operation();
        }
    }

    @Override
    public void add(Component c) {
   
   
        children.add(c);
    }

    @Override
    public void remove(Component c) {
   
   
        children.remove(c);
    }

    @Override
    public Component getChild(int t) {
   
   
        return children.get(t);
    }
}

/**
 * @description: 树叶节点
 * @author: wjw
 * @date: 2022/4/3
 */
public class Leaf implements Component{
   
   
    private String name;

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

    @Override
    public void operation() {
   
   
        System.out.println("我是树叶节点:" + name);
    }

    @Override
    public void add(Component c) {
   
   

    }

    @Override
    public void remove(Component c) {
   
   

    }

    @Override
    public Component getChild(int t) {
   
   
        return null;
    }
}
/**
 * @description: 客户端类
 * @author: wjw
 * @date: 2022/4/3
 */
public class Client {
   
   
    public static void main(String[] args) {
   
   
        Component component = new Composite();
        Component leaf1 = new Leaf("1");
        Component leaf2 = new Leaf("2");
        component.add(leaf1);
        component.add(leaf2);
        component.operation();
        component.getChild(1).operation();
        //这里树叶构件能调用add方法就会造成安全隐患
        leaf1.add(leaf1);
    }
}

客户端运行结果:

我是树叶节点:1
我是树叶节点:2
我是树叶节点:2

1.2.2 安全式组合模式实现

/**
 * @description: 安全式抽象构件
 * @author: wjw
 * @date: 2022/4/3
 */
public interface Component {
   
   

    /**公共操作方法**/
   void operation();
}

/**
 * @description: 树枝节点
 * @author: wjw
 * @date: 2022/4/3
 */
public class Composite implements Component{
   
   

    private ArrayList<Component> children = new ArrayList<>();

    @Override
    public void operation() {
   
   
        for (Component child : children) {
   
   
            child.operation();
        }
    }


    public void add(Component c) {
   
   
        children.add(c);
    }


    public void remove(Component c) {
   
   
        children.remove(c);
    }


    public Component getChild(int t) {
   
   
        return children.get(t);
    }
}

/**
 * @description: 树叶节点
 * @author: wjw
 * @date: 2022/4/3
 */
public class Leaf implements Component{
   
   
    private String name;

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

    @Override
    public void operation() {
   
   
        System.out.println("我是树叶节点:" + name);
    }

}

/**
 * @description: 客户端类
 * @author: wjw
 * @date: 2022/4/3
 */
public class Client {
   
   
    public static void main(String[] args) {
   
   
        Composite composite = new Composite();
        Leaf leaf1 = new Leaf("1");
        Leaf leaf2 = new Leaf("2");
        composite.add(leaf1);
        composite.add(leaf2);
        composite.operation();
    }
}

客户端测试结果:

我是树叶节点:1
我是树叶节点:2

二、组合模式应用场景

组合模式常见的应用场景主要是出现树形结构的地方,比如文件目录,公司人员架构图等等

2.1 公司人员架构

比如按照部门和员工组织成树形结构,可以统一处理薪资:

image-20220403152352420

/**
 * @description: 人力资源抽象构件
 * @author: wjw
 * @date: 2022/4/3
 */
public abstract class HumanResource {
   
   
    protected long id;
    protected double salary;

    public HumanResource(long id) {
   
   
        this.id = id;
    }

    public long getId() {
   
   
        return id;
    }

    /**
     * 计算工资
     * @return 工资结果
     */
    public abstract double calculateSalary();
}

/**
 * @description: 部门树枝构件
 * @author: wjw
 * @date: 2022/4/3
 */
public class Department extends HumanResource{
   
   

    private List<HumanResource> humanResources = new ArrayList<>();

    public Department(long id) {
   
   
        super(id);
    }

    @Override
    public double calculateSalary() {
   
   
        double totalSalary = 0;
        for (HumanResource humanResource : humanResources) {
   
   
            totalSalary += humanResource.calculateSalary();
        }
        this.salary = totalSalary;
        return totalSalary;
    }

    public void addHumanResource(HumanResource humanResource) {
   
   
        humanResources.add(humanResource);
    }
}
/**
 * @description: 员工树叶构件
 * @author: wjw
 * @date: 2022/4/3
 */
public class Employee extends HumanResource{
   
   

    public Employee(long id, double salary) {
   
   
        super(id);
        this.salary = salary;
    }

    @Override
    public double calculateSalary() {
   
   
        return salary;
    }
}

参考资料

《设计模式之美》

http://c.biancheng.net/view/1373.html

《Java 设计模式》

《设计模式:可复用面向对象软件的基础》

目录
相关文章
|
20天前
|
设计模式 Java 开发者
设计模式揭秘:Java世界的七大奇迹
【4月更文挑战第7天】探索Java设计模式:单例、工厂方法、抽象工厂、建造者、原型、适配器和观察者,助你构建健壮、灵活的软件系统。了解这些模式如何提升代码复用、可维护性,以及在特定场景下的应用,如资源管理、接口兼容和事件监听。掌握设计模式,但也需根据实际情况权衡,打造高效、优雅的软件解决方案。
|
21天前
|
设计模式 存储 Java
23种设计模式,享元模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享技术有效地支持大量细粒度对象的重用。这个模式在处理大量对象时非常有用,特别是当这些对象中的许多实例实际上可以共享相同的状态时,从而可以减少内存占用,提高程序效率
35 4
|
21天前
|
设计模式 Java 中间件
23种设计模式,适配器模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要目标是让原本由于接口不匹配而不能一起工作的类可以一起工作。适配器模式主要有两种形式:类适配器和对象适配器。类适配器模式通过继承来实现适配,而对象适配器模式则通过组合来实现
31 4
|
25天前
|
设计模式 Java 数据库
Java设计模式精讲:让代码更优雅、更可维护
【4月更文挑战第2天】**设计模式是解决软件设计问题的成熟方案,分为创建型、结构型和行为型。Java中的单例模式确保类仅有一个实例,工厂方法模式让子类决定实例化哪个类。适配器模式则协调不兼容接口间的合作。观察者模式实现了一对多依赖,状态变化时自动通知相关对象。学习和适当应用设计模式能提升代码质量和可维护性,但需避免过度使用。设计模式的掌握源于实践与不断学习。**
Java设计模式精讲:让代码更优雅、更可维护
|
20天前
|
设计模式 监控 Java
设计模式 - 观察者模式(Observer):Java中的战术与策略
【4月更文挑战第7天】观察者模式是构建可维护、可扩展系统的关键,它在Java中通过`Observable`和`Observer`实现对象间一对多的依赖关系,常用于事件处理、数据绑定和同步。该模式支持事件驱动架构、数据同步和实时系统,但需注意避免循环依赖、控制通知粒度,并关注性能和内存泄漏问题。通过明确角色、使用抽象和管理观察者注册,可最大化其效果。
|
3天前
|
设计模式 算法 Java
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
|
3天前
|
设计模式 JavaScript Java
[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式
[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式
|
3天前
|
设计模式 存储 JavaScript
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
|
3天前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式
|
3天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式