设计模式(九):组合模式

Published on 2024-03-08 14:59 in 分类: 博客 with 狂盗一枝梅
分类: 博客

一、组合模式的定义

组合模式(Composite Pattern)也叫合成模式,有时又叫做部分-整体模式(Part-Whole),主要是用来描述部分与整体的关系,其定义如下:Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.(将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

这个定义谁看完谁迷糊。。什么叫做“对单个对象和组合对象的使用具有一致性”,“一致性”是啥意思?

组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组织成树形结构,在这个树形结构中有两种类型的对象:叶子对象(Leaf)和容器对象(Composite)。叶子对象是组合中的基本单元,它没有子对象。容器对象可以包含叶子对象和其他容器对象,形成一个递归的树形结构。

组合模式定义了一个通用的组件接口,该接口声明了对叶子对象和容器对象进行操作的方法。叶子对象和容器对象都实现了这个接口,但是对于容器对象,它的实现中可能还包含了对子对象的管理操作,比如添加、删除和遍历子对象等。

通过使用组合模式,你可以将单个对象和组合对象都视为一个组件,客户端无需区分处理单个对象还是组合对象,可以一致地对待它们(这就是所谓的一致性)。这样简化了客户端的代码,同时也提供了灵活性,可以动态地增加、删除和修改对象的组合结构。

组合模式的通用类图如下所示:

image-20240308100803278

1、组合模式中的角色

  • Component:这是组合模式中的对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理 Component子部件,Component 可以是抽象类或者接口
  • Leaf : 在组合中表示叶子节点,叶子节点没有子节点 ,是最末端的存放数据的结构
  • Composite:非叶子节点, 用于存储子部件,在 Component 接口中实现子部件的相关操作,比如增加(add),删除 (remove)

2、组合模式解决的问题

组合模式主要用于处理对象的层次结构和组合关系,将对象组织成树形结构,并以一致的方式处理单个对象和对象组合。

也就是说,组合模式解决这样的场景,当我们的要处理的对象可以生成一颗树形结构,而我们要对树上的节点和叶子进行操作时,组合模式能够提供一致的方式,而不用考虑它是节点还是叶子。

aComposite

二、组合模式案例

案例:在一个页面展示院校-学院-专业。一个学校会有多个学院, 一个学院有会多个专业,它的组织结构图就是一个很标准的树状结构

XXX大学组织架构

使用组合模式实现该案例,类图如下

组合模式类图.drawio

OrganizationComponent

public abstract class OrganizationComponent {

    private String name;

    public String getName() {
        return name;
    }

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

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

    public void add(OrganizationComponent component) {
        throw new UnsupportedOperationException();
    }

    public void remove(OrganizationComponent component) {
        throw new UnsupportedOperationException();
    }

    public abstract void show();
}

School

学校类

public class School extends OrganizationComponent {

    /**
     * 组合的是学院
     */
    List<OrganizationComponent> componentList = new ArrayList<>();

    public School(String name) {
        super(name);
    }

    @Override
    public void add(OrganizationComponent component) {
        componentList.add(component);
    }

    @Override
    public void remove(OrganizationComponent component) {
        componentList.remove(component);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public void show() {
        System.out.println("----"+getName()+"----");
        for (OrganizationComponent organizationComponent : componentList) {
            organizationComponent.show();
        }
    }
}

College

学院类

public class College extends OrganizationComponent {

    /**
     * 组合的是专业
     */
    List<OrganizationComponent> componentList = new ArrayList<>();

    public College(String name) {
        super(name);
    }

    @Override
    public void add(OrganizationComponent component) {
        componentList.add(component);
    }


    @Override
    public void remove(OrganizationComponent component) {
        componentList.remove(component);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public void show() {
        System.out.println("----"+getName()+"----");
        for (OrganizationComponent organizationComponent : componentList) {
            organizationComponent.show();
        }
    }
}

Majar

专业类

public class Majar extends OrganizationComponent {

    public Majar(String name) {
        super(name);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public void show() {
        System.out.println(getName());
    }
}

启动类

public class Client {

    public static void main(String[] args) {
        OrganizationComponent school = new School("清华大学");
        OrganizationComponent computerCollege = new College("计算机学院");
        OrganizationComponent infoCollege = new College("外国语学院");
        school.add(computerCollege);
        school.add(infoCollege);
        computerCollege.add(new Majar("计算机科学与技术专业"));
        computerCollege.add(new Majar("软件工程专业"));
        infoCollege.add(new Majar("英语专业"));
        infoCollege.add(new Majar("日语专业"));
        infoCollege.add(new Majar("俄语专业"));
        school.show();
    }
}

运行结果

----清华大学----
----计算机学院----
计算机科学与技术专业
软件工程专业
----外国语学院----
英语专业
日语专业
俄语专业

三、组合模式优缺点

组合模式优点:

  • 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,屏蔽了对象系统的层次差异性,使用一致的行为控制不同层次
  • 扩展性非常高,可以很方便地增加 树枝节点叶子节点 对象,并对现有类库无侵入,满足“开闭原则”

组合模式缺点:

要求较高的抽象性,如果叶子和节点有很多差异性的话,例如很多属性和方法都不一样,不适合使用组合模式,而本案例院校展示,他们很多属性和方法都是共同的,类似一个树形结构

四、源码中的组合模式

比如Java AWT 和 Swing GUI 库:Java AWT(Abstract Window Toolkit)和 Swing 是 Java 编程语言中用于创建图形用户界面(GUI)的库。它们使用了组合模式来构建 GUI 组件的层次结构,例如窗口、面板、按钮、文本框等。这些组件可以嵌套在彼此之内,形成一个树形结构,并以一致的方式进行操作和管理。

。。没啥好说的,这个组合模式真是有点奇怪,就太过于简单以至于不知道该说点什么好,我们自己封装的TreeUtil工具类不都用了组合模式



END.


#设计模式
目录