组合模式

定义一个类(或抽象类),类里面有一堆的自己,进行各种操作,适合树形结构的场景

  • 定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使得客户端对单个对象和组合对象保持一致的处理方式
  • 类型:结构型
  • 适用场景:
    •   客户端可以忽略组合对象与单个对象的差异时
    •   处理一个树形结构时
  • 优点:
    •   清楚的定义分层次的复杂对象,表示对象的全部或部分层次
    •   让客户端忽略了层次的差异,方便对整个层次结构进行控制
    •   简化客户端代码
    •   符合开闭原则
  • 缺点:
    •   限制类型时会比较复杂
    •   使设计变得更加抽象
  • 相关设计模式:
    •   组合模式和访问者模式:进行组合应用,可以使用访问者模式访问组合模式的递归结构

Coding

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

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

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

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

    public void print(){
        throw new UnsupportedOperationException("不支持打印操作");
    }
}
/**
 * 课程信息
 */
public class Course extends AbCatalogComponent {
    private String name;
    private double price;

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

    public String getName(AbstractDecorator catalogComponent) {
        return this.name;
    }

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

    @Override
    public void print() {
        System.out.println("Course Name:" + name + " Price:" + price);
    }
}
public class CourseCatalog extends AbCatalogComponent {
    private List<AbCatalogComponent> items = new ArrayList<AbCatalogComponent>();
    private String name;
    private Integer level;

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

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

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

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

    @Override
    public void print() {
        System.out.println(this.name);
        for (AbCatalogComponent 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) {
        AbCatalogComponent linuxCourse = new Course("Linux课程",11);
        AbCatalogComponent windowsCourse = new Course("Windows课程",11);

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

        AbCatalogComponent mmallCourse1 = new Course("Java电商一期",55);
        AbCatalogComponent mmallCourse2 = new Course("Java电商二期",66);
        AbCatalogComponent designPattern = new Course("Java设计模式",77);

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

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

        imoocMainCourseCatalog.print();
    }
}
===============打印结果====================
课程主目录
  Course Name:Linux课程 Price:11.0
  Course Name:Windows课程 Price:11.0
  Java课程目录
    Course Name:Java电商一期 Price:55.0
    Course Name:Java电商二期 Price:66.0
    Course Name:Java设计模式 Price:77.0

UML

说明:可以看代码或者UML类图,其核心在于类目和课程都继承了相同的类,然后类目中一对多组合了它们的基类对象,这就使得类目中可以添加课程也可以添加类目,要注意的问题是不同层次的类目或课程如果要做分层显示(比如每多一个子类层次,前面空格增加),是需要多做处理的,比如传入某个层级的值对不同层级做不同处理等

源码中的应用

  • java.awt.Container:可以看到add方法,添加了它的一个父类
public class Container extends Component {
    ...
    public Component add(Component comp) {
        addImpl(comp, null, -1);
        return comp;
    }
    ...
}
  • org.apache.ibatis.scripting.xmltags.MixedSqlNode:MyBatis中拼装各种sql用的模式就是组合模式
public class MixedSqlNode implements SqlNode {
    private List<SqlNode> contents;

    public MixedSqlNode(List<SqlNode> contents) {
        this.contents = contents;
    }

    public boolean apply(DynamicContext context) {
        Iterator i$ = this.contents.iterator();

        while(i$.hasNext()) {
            SqlNode sqlNode = (SqlNode)i$.next();
            sqlNode.apply(context);
        }
        return true;
    }
}

 

posted @ 2024-01-19 11:29  wangzhilei  阅读(28)  评论(0)    收藏  举报