组合模式详解 (附java语言源码)

组合模式(Composite Pattern)

将对象组合成树形结构以表示“部分-整体”的层次结构。Composite 使得客户对单个对象和复合对象的使用具有一致性。(Compose object into tree structures torepresent part-whole hierarchy. Composite lets clients treat individual objectsand compositions of objects uniformly.)

组合模式的优缺点
优点:

  1. 可以清楚地定义分层次的复杂类型,表示对象的全部层次或者部分层次 ,它让客户端忽略了层次的差异,方便对整个层次经行控制。
  2. 客户端可以一致的使用一个组合模式或对单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端的代码。
  3. 在组合模式种增加新的容器构件和叶子构件都很方便,无需对现有类库进行任何修改,符合开闭原则。
  4. 为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合可以形成复杂的树形机构,但对树形结构的控制却很简单。

缺点:

在增加新的构件时就比较难咯。而且难以限定,有时候希望在一个容器种能有某些特定的对象,例如在某个文件夹只能有image或者gif等。这个就比较难以实现。

开发中的应用场景

  1. 操作系统的资源管理器
  2. GUI中的容器层次图
  3. XML文件解析
  4. OA系统中,组织结构的处理
  5. Junit单元测试框架 : 底层设计就是典型的组合模式,TestCase(叶子)、TestUnite(容器)、Test接口(抽象)
    组合模式详解 (附java语言源码)_第1张图片

组合模式核心

  1. component (抽象构件:容器):它可以是接口或者抽象类,为叶子构建和子容器构建对象声明接口,在该角色中可以包含所有子类共有的行为的实现和声明。在抽象构建中定义了访问及管理它的子构件的方法,如增加子构件,删除子构件,获取子构件等。它定义了叶子和容器构件的共同点
  2. leaf(叶子构建):叶子构建可以说就是各种类型的文件!叶子构建没有子构件。它实现了抽象构建中的定义的行为。对于那些访问子容器,删除子容器,增加子容器的就报错。
  3. compsite(子容器构建):它在组合模式中表示容器节点对象,容器结点是子节点,可以是子容器,也可以是叶子构建,它提供一个集合来存储子节点。它有容器特征,可以包含子节点

案例:使用组合模式,模拟杀毒软件,该软件能够对某个文件夹杀毒,也可以指定对某些文件杀毒。该过程大致可分为4步,代码如下:
步骤1:定义AbstractFile : 抽象文件类,充当抽象构建。

/**
 * AbstractFile: 抽象文件类,充当抽象构建。
 */
public abstract class AbstractFiles {
    public abstract void add(AbstractFiles af);
    public abstract void remove(AbstractFiles af);
    public abstract AbstractFiles get(int  i);
    public abstract void killVirus();
}

步骤2:定义叶子节点:文件类型,在此只写了图片文件。

/**
 * 图片文件,继承自AbstractFiles
 */
public class ImageFile extends AbstractFiles {

    private String name;

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

    @Override
    public void add(AbstractFiles af) {
        System.out.println("不支持该方法");
    }

    @Override
    public void remove(AbstractFiles af) {
        System.out.println("不支持该方法");
    }

    @Override
    public AbstractFiles get(int i) {
        System.out.println("不支持该方法");
        return null;
    }

    @Override
    public void killVirus() {
        System.out.println("开始进行--"+name+"--文件杀毒");
    }
}

步骤3:文件夹类型

import java.util.ArrayList;

/**
 * 文件夹类型 ,继承自AbstractFiles
 */
public class Folder extends AbstractFiles {

    //文件夹类,所有的都可以用
    private ArrayList<AbstractFiles> list = new ArrayList<AbstractFiles>();
    private String name;
    public Folder(String name) {
        this.name=name;
    }

    @Override
    public void add(AbstractFiles af) {
        list.add(af);
        System.out.println("添加文件成功!");
    }

    @Override
    public void remove(AbstractFiles af) {
        if(list.remove(af)) {
            System.out.println("删除成功");
        }else{
            System.out.println("删除失败");
        }
    }

    @Override
    public AbstractFiles get(int i) {
        return list.get(i);
    }

    @Override
    public void killVirus() {
        System.out.println("对文件夹 "+name+" 进行杀毒");
        //递归调用
        for(Object o:list) {
            ((AbstractFiles) o).killVirus();
        }
    }
}

步骤4:测试

/**
 * 测试
 */
public class Client {
    public static void main(String[] args) {
        //创建一个文件类型
        AbstractFiles f1 = new Folder("主文件夹");
        //创建文件
        AbstractFiles file1= new ImageFile("美妙月亮。png");
        AbstractFiles file2= new ImageFile("大海.jpg");
        AbstractFiles file3= new ImageFile("沙漠杨树.gif");
        f1.add(file1);
        f1.add(file2);
        f1.add(file3);
        //file1.killVirus();
        f1.killVirus();

    }
}

测试结果如下图所示:
组合模式详解 (附java语言源码)_第2张图片

如果想了解更多设计模式,可点击:设计模式概述 以及 23种设计模式的介绍

你可能感兴趣的:(设计模式实战案例)