二哈谈设计模式之组合模式

组合模式



前言

组合模式体现了整体与部分的关系,其典型的应用就是树形结构,其表示“整体-部分”的层次结构。
组合模式核心:

  • 抽象构件角色:定义了叶子和容器构件的共同点
  • 叶子构件角色:无子节点
  • 容器构件角色:有容器特征,可以包含子节点

一、场景

使用Composite模式来实现文件系统的”文件/目录“结构,需要规划的类如下:

  • Root:File与Folder的共同接口界面。
  • Folder:目录。目录下有子目录、文件。
  • File:文件。存在与目录之下。
  • Client:测试类

二、具体实现

1.透明方式

(1)Root类

/**
 * 统一Root接口
 */
interface Root {
    public boolean addFile(Root file);
    public boolean removeFile(Root file);
    public List<Root> getFile();
    public void display();

}

(2)File类

/**
 * 文件类
 */
public class File implements Root {

    String name;

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

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

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

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

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

(3)Folder类

public class Folder implements Root {

    String name;
    List<Root> folder;

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

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

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

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

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

(4)测试类

public class Client {
    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");

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

        root1.display();
        root2.display();
    }
}

结果:
在这里插入图片描述
优点:所有的构件都有相同的接口,客户端可以同等对待所有对象。
缺点:不够安全,因为树叶类对象和组合对象在本质上是有区别的,其树叶类对象没有下一层次的对象,方法add()、remove()、getChild()是没有意义的,可能在运行期出错。

2.安全方式

(1)实现抽象文件角色

/**
 * 抽象文件角色
 */
public interface IRoot {

    //返回自己的实例
    IRoot getComposite();
    //某个商业方法
    void sampleOperation();
    //获取深度
    int getDeep();
    //设置深度
    void setDeep(int deep);
}

(2)实现文件夹角色

public class IFolder implements IRoot {

    private  String name;
    private int deep;
    private Vector<IRoot> componentVector = new Vector<>();

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

    @Override
    public IRoot getComposite() {
        return this;
    }

    @Override
    public void sampleOperation() {
        System.out.println("执行业务方法!");
    }

    @Override
    public int getDeep() {
        return deep;
    }

    @Override
    public void setDeep(int deep) {
        this.deep = deep;
    }

    //增加一个文件或文件夹
    public void add(IRoot iRoot){
        componentVector.add(iRoot);
        iRoot.setDeep(this.deep+1);
    }
    //删除一个文件或文件夹
    public void remove(IRoot iRoot){
        componentVector.removeElement(iRoot);
    }
    //返回直接子文件集合
    public Vector getAllFile(){
        return componentVector;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

(3)实现文件类

/**
 * 文件
 */
public class IFile implements IRoot{
    private String name ;
    private int deep;

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

    @Override
    public IRoot getComposite() {
        return this;
    }

    @Override
    public void sampleOperation() {
        System.out.println("执行商业方法!");
    }

    @Override
    public int getDeep() {
        return deep;
    }

    @Override
    public void setDeep(int deep) {
        this.deep = deep;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

(4)测试类

public class Client2 {
    public static String indentChar = "\t";

    public static void main(String[] args) {
        new Client2().test();
    }

    public void test(){
        //根下文件及文件夹
        IFolder root = new IFolder("树根");
        IFolder b1_1 = new IFolder("1_枝1");
        IFolder b1_2 = new IFolder("1_枝2");
        IFolder b1_3 = new IFolder("1_枝3");
        IFile l1_1 = new IFile("1_叶1");
        IFile l1_2 = new IFile("1_叶2");
        IFile l1_3 = new IFile("1_叶3");
        //b1_2下的文件及文件夹
        IFolder b2_1 = new IFolder("2_枝1");
        IFolder b2_2 = new IFolder("2_枝2");
        IFile l2_1 = new IFile("2_叶1");
        //缔造树的层次关系
        root.add(b1_1);
        root.add(b1_2);
        root.add(l1_1);
        root.add(l1_2);
        b1_2.add(b2_1);
        b1_2.add(b2_2);
        b1_2.add(l2_1);
        root.add(l1_3);
        root.add(b1_3);
        //打印数的层次
        outTree(root);
    }

    public void outTree(IFolder iFolder){
        System.out.println(iFolder.getName());
        iterateTree(iFolder);
    }

    public void iterateTree(IFolder ifolder){
        Vector<IRoot> clist = ifolder.getAllFile();
        for(Iterator<IRoot> it = clist.iterator();it.hasNext();){
            IRoot em = it.next();
            if(em instanceof IFolder){
                IFolder cm = (IFolder) em;
                System.out.println(getIndents(em.getDeep())+cm.getName());
                iterateTree(cm);
            }else {
                System.out.println(getIndents(em.getDeep())+((IFile)em).getName());
            }
        }
    }

    /**
     * 文件层次缩进字符串
     * @param x
     * @return
     */
    public static String getIndents(int x){
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<x;i++){
            sb.append(indentChar);
        }
        return sb.toString();
    }
}

结果:
在这里插入图片描述

优点:树叶类和合成类具有不同的接口,解决了透明方式的缺点,是个安全的方式。
缺点:不够透明

三、应用场景

  • 操作系统的资源管理器
  • GUI中的容器层次图-XML文件解析
  • OA系统中,组织结构的处理
  • Junit单元测试框架
    ·底层设计就是典型的组合模式,TestCase(叶子)、TestUnite(容器)、Test接口(抽象)

总结

组合模式是为了简化编程而提出的,在如下情况可以考虑使用组合模式:
– 需要描述对象的部分和整体的等级结构
– 需要客户端忽略掉个体构件和组合构件的区别。客户端必须平等对待所有的构件,包含个体构件和组合构件。

优点是很容易地增加新种类的构件,使客户端很容易设计,因为客户端不需要知道构件是树叶构件还是树枝构件;缺点是当使用组合模式后,用继承的方法来增加新的行为会很困难。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值