设计模式(七)组合模式

概念

组合模式,也被称作合成型模式或者Composite模式,将对象组合成树形结构以表示“整体-部分”的层次关系。组合涉及的是一组对象,其中有的对象可能含有其他的对象(对象群组),而有的只是单个对象(叶子Leaf)。

组合模式涉及目的:让用户能够用统一的接口来处理单个对象以及组合对象。

例如:文件系统,一个文件路径下既包含单独的文件,也包含其他的文件夹,而这些文件夹下又包含别的文件和文件夹。这是一个典型的组合模式的树形结构,文件夹==组合对象,文件==单个对象。而用户可以通过类似的方式遍历文件夹和文件。

组合模式角色结构

  • 抽象构建角色(Component):定义共有接口及其默认行为。
  • 树叶结构角色(Leaf):代表参加组合的树叶对象(单个对象),定义参加组合的原始对象的行为。
  • 树枝构建角色(Componsite):有子对象的对象(对象组合),定义树枝结构对象行为。

组合模式的两种形式

  • 透明方式:Component里面申明所有用来管理子对象的方法
    • 优点:所有构建类都有相同的接口,组合对象与单个对象的区别在接口层次上消失了,客户端可以同等的对待所有的对象;
    • 缺点:不安全,树叶类对象没有下一个层次的对象,这样的话有一些方法(add(),remove())等操作没有意义,这种编译是不会报错,但运行时会出错。
  • 安全方式:在Componsite类里声明所有的用来管理子类对象的方法。
    • 优点:这样做是安全的,因为树叶类型的对象没有管理子类对象的方法,如果客户端对树叶类对象使用这些方法时,编译时会出错,这样程序就到不了运行阶段。
    • 缺点:不够透明,树叶类和合成类具有不同的接口。

使用组合模式的注意事项

  • 明显的给出父类对象的引用,在子对象给出父对象的引用,这样比较容易遍历所有的父对象;
  • 在通常的系统里,可以使用享元模式实现构件的共享,但由于组合模式中包含对父对象的引用,该共享不容易实现;
  • 有时系统需要对一个树枝构件遍历很多次,这时可以把遍历子构件的结果作为缓存暂时存放在父构件里;
  • 可以用Vector或者其他数组的聚集存储子对象;
  • 客户端不应该直接调用树叶类,应该由其父类向树叶类进行委派,这样可以增强代码的复用性。

示例说明

简单实现文件系统的文件/目录结构

/**
 * Component接口
 */
public interface Root {
    boolean addFile(Root file);
    boolean removeFile(Root file);
    void disPlay();
    List<Root> getFile();
}

/**
 * Componsite实现-其种包含子文件夹和文件
 */
class Folder implements Root{
    String name;
    List<Root> folder;

    public Folder(String name) {
        this.folder = new ArrayList<>();
        this.name = name;
    }

    @Override
    public boolean addFile(Root file) {
        return folder.add(file);
    }

    @Override
    public void disPlay() {
        System.out.println(name);
        for (Root file : folder) {
            if(file instanceof Folder){
                System.out.print("|__");
            }
            file.disPlay();
        }
    }

    @Override
    public List<Root> getFile() {
        return folder;
    }

    @Override
    public boolean removeFile(Root file) {
        return folder.remove(file);
    }
}

/**
 * Leaf-存在于文件夹下的文件
 */
class File implements Root{
    String name;

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

    @Override
    public boolean addFile(Root file) {
        return false;
    }

    @Override
    public void disPlay() {
        System.out.println("  |__" + name);
    }

    @Override
    public List<Root> getFile() {
        return null;
    }

    @Override
    public boolean removeFile(Root file) {
        return false;
    }
}

class CompositeClient{
    public static void main(String[] args){
        Root root1 = new Folder("c://");
        Root root2 = new Folder("d://");
        Root win = new Folder("windows");
        Root sys = new Folder("system");
        Root hw = new File("HelloWorld.java");
        Root picture = new File("picture.png");

        root1.addFile(win);
        root1.addFile(sys);
        win.addFile(hw);
        win.addFile(picture);

        root1.disPlay();
        System.out.println("****************************");
        root1.removeFile(win);
        root1.disPlay();
        System.out.println("============================");
        root2.disPlay();
    }
}
运行结果:

c://
|__windows
  |__HelloWorld.java
  |__picture.png
|__system
****************************
c://
|__system
============================
d://

应用场景

  • 需要描述对象的部分和整体的等级结构
  • 需要客户端忽略掉个体构建和组合构建的区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值