天天看点

设计模式-组合模式(Composite Pattern)

推荐:​​Java设计模式汇总​​

组合模式

定义

Compose objects into tree structures to represent part-whole hierarchies. Composite let client treat individual objects and compositions of objects uniformly.

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

类型

结构性。

模式讲解

抽象根节点(Component):定义系统各层对象的共有方法和属性,可以预先定义一些默认行为和属性。

树枝节点(Composite):定义树枝节点的行为,还需要存储子节点,组合树枝节点和叶子节点形成一个树形结构。

叶子节点(Leaf):叶子节点对象,其下再无分支,是系统层次遍历的最小单位。

设计模式-组合模式(Composite Pattern)

例子

这里的例子是一个课程目录例子,比如主课程目录中有Java课程目录、Python课程目录等,而Java课程目录中还有Java设计模式课程、Java虚拟机课程、SpringBoot框架课程等等更细分的课程,或者还有其他Java课程子目录。

CatalogComponent类(抽象类,目录组件类),是抽象根节点(Component),预先定义了一些默认行为和属性。

package com.kaven.design.pattern.structural.composite;

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

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

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

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

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

Course类(课程类),继承了CatalogComponent类,并且重写了它需要的方法,是叶子节点(Leaf)。

package com.kaven.design.pattern.structural.composite;

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() {
        return this.name;
    }

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

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

CourseCatalog类(课程目录类),继承了CatalogComponent类,也重写了它需要的方法,因为它是目录(树枝节点),所以它有一个容器​

​private List<CatalogComponent> items = new ArrayList<CatalogComponent>()​

​​,用来存储课程(叶子节点),所以它是是树枝节点(Composite)。

​​

​level是目录的级数​

​,方便打印目录结构。

package com.kaven.design.pattern.structural.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 String getName() {
        return this.name;
    }

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

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

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

应用层代码:

package com.kaven.design.pattern.structural.composite;

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

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

        CatalogComponent designPattern = new Course("Java设计模式",20);
        CatalogComponent springboot = new Course("springboot框架",17);
        CatalogComponent springcloud = new Course("springcloud框架",19);

        javaCourseCatalog.add(designPattern);
        javaCourseCatalog.add(springboot);
        javaCourseCatalog.add(springcloud);

        CatalogComponent mainCourseCatalog = new CourseCatalog("课程主目录",1);

        mainCourseCatalog.add(linuxCourse);
        mainCourseCatalog.add(windowsCourse);
        mainCourseCatalog.add(javaCourseCatalog);

        mainCourseCatalog.print();

    }
}      

输出:

课程主目录
  Course Name:Linux课程 Price:11.0
  Course Name:Windows课程 Price:12.0
  Java课程目录
    Course Name:Java设计模式 Price:20.0
    Course Name:springboot框架 Price:17.0
    Course Name:springcloud框架 Price:19.0      

这里便完成了一个简单的组合模式例子。

适用场景

  • 系统对象层次具备整体和部分,呈树形结构,且要求具备统一行为(如树形菜单、操作系统目录结构等)。
  • 从一个整体中能够独立出部分模块或功能的场景。

优点

  • 组合模式屏蔽了对象系统的层次差异性(树节点和叶子节点为不同类型),将应用层代码与复杂的容器对象解耦,使得应用层可以忽略层次间的差异,使用一致的行为控制不同层次。
  • 组合模式可以很方便地增加​

    ​树枝节点​

    ​​和​

    ​叶子节点​

    ​​对象,并对现有类库无侵入,符合​

    ​开闭原则​

    ​。
  • 一棵树形结构中的所有节点都是Component,局部和整体对调用者来说没有任何区别,高层模块不必关心自己处理的是单个对象还是整个组合结构。
  • 节点自由增加。

缺点

  • 如果类系统(树形结构)过于庞大,虽然对不同层次都提供一致性操作,但应用层仍需花费时间理清类之间的层次关系。
  • 使用组合模式时,其叶子节点和树枝节点的声明都是实现类,而不是接口,违反了​

    ​依赖倒置原则​

    ​。