【Java设计模式】组合模式


✍ 对于 树形结构 ,当容器对象(如文件夹)的某一个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象(可以是容器对象,也可以是叶子对象,如子文件夹和文件)并调用执行。 (递归调用)。由于容器对象和叶子对象在功能上的区别,在使用这些对象的客户端代码中必须 有区别地对待容器对象和叶子对象 ,而实际上 大多数情况下客户端希望一致地处理它们 , 因为对于这些对象的区别对待将会使得程序非常复杂

组合模式描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分 ,可以 一致地对待容器对象和叶子对象,这就是组合模式的模式动机。

给组合模式下个定义的话如下:

组合模式(Composite Pattern) :组合多个对象形成 树形结构表示“整体- 部分”的结构层次 。组合模式对单个对象(即叶子对象)组合对象(即容器对象) 的使用具有一致性 。组合模式又可以称为“整体- 部分”(Part-Whole) 模式 ,属于对象的结构模式,它将对象组织到树结构中,可以用来描述整体与部分的关系 。

组合模式包含如下角色:
• Component: 抽象构件: 它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由叶子构件完成。
• Leaf: 叶子构件 :是组合中的叶节点对象,它没有子节点,用于实现抽象构件角色中 声明的公共接口。
• Composite: 容器构件:是组合中的分支节点对象,它有子节点。它实现了抽象构件角色中声明的接口,它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

✍ 演示一下:

创建目录组件的抽象类( Component: 抽象构件)

//目录组件
public abstract class CatalogComponent {
    public void add(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持添加操作");
    }

    public void remove(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持删除操作");
    }


    public String getName(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持获取名称操作");
    }


    public double getPrice(CatalogComponent catalogComponent){
        throw new UnsupportedOperationException("不支持获取价格操作");
    }


    public void print(){
        throw new UnsupportedOperationException("不支持打印操作");
    }

}

创建继承该类的课程(相当于菜单) (Leaf: 叶子构件 )

public class Course extends CatalogComponent {
    private String name;  //课程名称
    private double price;  //课程价格

    public Course(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public double getPrice(CatalogComponent catalogComponent) {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println("Course Name:"+name+" Price:"+price);
    }

}

创建继承抽象类的目录( Composite: 容器构件)

import java.util.ArrayList;
import java.util.List;

public class CourseCatalog extends CatalogComponent {
    //目录组件
    private List<CatalogComponent> items = new ArrayList<CatalogComponent>();
    private String name;  //目录名称
    private Integer level;  //目录级别


    public CourseCatalog(String name,Integer level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public void add(CatalogComponent catalogComponent) {
        items.add(catalogComponent);
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        items.remove(catalogComponent);
    }

    @Override
    public void print() {
        System.out.println(this.name);
        for(CatalogComponent catalogComponent : items){
            if(this.level != null){
                for(int  i = 0; i < this.level; i++){
                    System.out.print("  ");
                }
            }
            catalogComponent.print();
        }
    }

}

测试类:

public class Test {
    public static void main(String[] args) {
        CatalogComponent linuxCourse = new Course("Linux课程",11);
        CatalogComponent windowsCourse = new Course("Windows课程",11);

        CatalogComponent javaCourseCatalog = new CourseCatalog("Java课程目录",2);

        CatalogComponent mmallCourse1 = new Course("Java网络编程",55);
        CatalogComponent mmallCourse2 = new Course("Java编程思想",66);
        CatalogComponent designPattern = new Course("Java设计模式",77);

        javaCourseCatalog.add(mmallCourse1);
        javaCourseCatalog.add(mmallCourse2);
        javaCourseCatalog.add(designPattern);

        CatalogComponent imoocMainCourseCatalog = new CourseCatalog("计算机课程主目录",1);
        imoocMainCourseCatalog.add(linuxCourse);
        imoocMainCourseCatalog.add(windowsCourse);
        imoocMainCourseCatalog.add(javaCourseCatalog);

        imoocMainCourseCatalog.print();
    }
}

结果:
在这里插入图片描述

UML图:
在这里插入图片描述
这里屏蔽了细节 很容易发现树形结构
CatalogComponent是抽象类
CourseCatalog是抽象类的实现类 负责了目录的级别
Course也是抽象类的实现类,负责了菜单

目录界别 加 菜单内容 组合成目录
这里起到关键作用的是 抽象类 和分离组合的思想

看一下没有屏蔽细节的UML
在这里插入图片描述
换一种角度
在这里插入图片描述

组合模式的关键是 定义了一个抽象构件类 , 它既可以代表叶子 , 又可以代表容器 , 而 客户端针对该抽象构件类进行编程 , 无须知道它到底表示的是叶子还是容器 , 可以对其进行统一处理 。 同时 容器对象与抽象构件类之间还建立一个聚合关联关系 , 在容器对象中既可以包含叶子 , 也可以包含容器 , 以此 实现递归组合 , 形成一个树形结构

✍ 说一下它的优缺点:

组合模式的优点

  • 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。
  • 客户端调用简单,客户端可以一致的使用组合结构或其中单个对象。
  • 定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。
  • 更容易在组合体内加入对象构件,客户端不必因为加入了新的对象构件而更改原有代码。

组合模式的缺点

  • 使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联。
  • 增加新构件时可能会产生一些问题,很难对容器中的构件类型进行限制。

✍ 在以下情况下可以使用组合模式:

  • 需要表示一个对象整体或部分层次,在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,可以一致地对待它们。
  • 让客户能够忽略不同对象层次的变化,客户端可以针对抽象构件编程,无须关心对象层次结构的细节。
  • 对象的结构是动态的并且复杂程度不一样,但客户需要一致地处理它们。

✍ 它的应用还是比较广泛的:

XML解析;

操作系统中的目录结构 是一个树形结构,因此在对文件和文件夹进行操作时可以应用组合模式,例如杀毒软件在查毒或杀毒时,既可以针对一个具体文件,也可以针对一个目录。如果是对目录查毒或杀毒,将递归处理目录中的每一个子目录和文件。

JDK 的AWT/Swing 是组合模式在Java 类库中的一个典型实际应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值