java设计模式——组合模式

一. 定义与类型

定义:将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使客户端对单个对象和组合对象保持一致的方式处理

类型:结构性

假设有一个树形结构的菜单,而在菜单中还可能有子菜单,子菜单下还可能有子菜单,子菜单下还有文件等等, 这种情况下可以使用组合模式。

二. 使用场景

(1) 希望客户端可以忽略组合对象与单个对象的差异

(2) 处理一个树形结构

三. 优缺点

优点:

  (1) 清楚的定义层次的复杂对象,表示对象的全部或部分层次

  (2) 让客户端忽略了层次的差异,方便对整个层次结构进行控制

  (3) 简化客户端代码

  (4) 符合开闭原则

缺点:

  (1) 限制类型时会较为复杂

  (2) 使设计变得更加抽象

四. 相关设计模式

 组合模式和访问者模式

  可以使用访问者模式来访问组合模式的递归结构

五. Coding

以课程目录与课程为例,课程目录有目录名称,课程有名称与价格,它们不是同一类实体,但是它们可以组合成整体一套课程。

创建一个目录组件类:

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-12 11:36
 **/
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("不支持打印操作");
    }
}

创建一个课程类,继承组件类:

/**
 * @program: designModel
 * @description: 课程类
 * @author: YuKai Fan
 * @create: 2019-02-12 11:39
 **/
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);
    }
}

在创建一个课程目录类,也继承组件类:

/**
 * @program: designModel
 * @description: 课程目录类
 * @author: YuKai Fan
 * @create: 2019-02-12 11:41
 **/
public class CourseCatalog extends CatalogComponent{
    private List<CatalogComponent> items = new ArrayList<CatalogComponent>();
    private String name;public CourseCatalog(String name) {
        this.name = 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) {
           
                    System.out.print(" ");
                
            }
            catalogComponent.print();
        }
    }
}

应用层:

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-12 11:47
 **/
public class Test {
    public static void main(String[] args) {
        CatalogComponent linuxCourse = new Course("Linux课程", 11);
        CatalogComponent windowsCourse = new Course("Windows课程", 15);

        CatalogComponent javaCourseCatalog = new CourseCatalog("Java课程");

        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 mainCourseCatalog = new CourseCatalog("课程主目录");
        mainCourseCatalog.add(linuxCourse);
        mainCourseCatalog.add(windowsCourse);
        mainCourseCatalog.add(javaCourseCatalog);

        mainCourseCatalog.print();


    }
}

结果:

课程主目录
 Course Name:Linux课程Price:11.0
 Course Name:Windows课程Price:15.0
 Java课程
 Course Name:Java电商一期Price:55.0
 Course Name:Java电商二期Price:66.0
 Course Name:Java设计模式Price:77.0

Process finished with exit code 0

从上面的结果可以看出,java课程与课程主目录都属于目录,只不过等级不同,所以需要根据等级来动态的判断。例如一级目录,二级目录等等。

这些事组合模式的缺点,限制类型时会比较复杂。所以将上面代码进行改进。

课程目录类:

/**
 * @program: designModel
 * @description: 课程目录类
 * @author: YuKai Fan
 * @create: 2019-02-12 11:41
 **/
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 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();
        }
    }
}

应用层:

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-12 11:47
 **/
public class Test {
    public static void main(String[] args) {
        CatalogComponent linuxCourse = new Course("Linux课程", 11);
        CatalogComponent windowsCourse = new Course("Windows课程", 15);

        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 mainCourseCatalog = new CourseCatalog("课程主目录",1);
        mainCourseCatalog.add(linuxCourse);
        mainCourseCatalog.add(windowsCourse);
        mainCourseCatalog.add(javaCourseCatalog);

        mainCourseCatalog.print();


    }
}

结果:

UML类图:

组合模式将多个对象组合成树形结构以表示“整体-部分”的结构层次。组合模式对单个对象(叶子对象)和组合对象(容器对象)的使用具有一致性。

 六. 源码分析

(1)jdk

List中的ArrayList中的addAll()方法,以及HashMap中的putAll方法都是通过继承方式的组合模式体现

(2)mybatis

SqlNode接口,该接口有很多的实现类,都是通过组合模式将多个sqlNode结合到一起(有的是组合关系,有的不是)。

原文地址:https://www.cnblogs.com/FanJava/p/10364322.html