组合模式(Composite)

2020-04-17  本文已影响0人  吉他手_c156

组合(composite)模式的定义,组合模式又叫做 “部分-整体” 模式,他是一种将对象组合成树状层次结构的模式,用来表示 “部分-整体” 的关系,使用户对单个对象和组合对象具有一致的访问性,组合模式属于结构型模式

组合模式的结构与特点

1.比如公司的组织架构就是一颗树,总部下来会有财务,行政,人力,研发,市场等部门,每个部门下有会有不同的子部门
2.在比如文件结构,整体文件结构是一个树形结构,目录和文件,一个目录下面又会有子目录或者文件

组合模式的使用场景

1.希望客户端可以忽略组合对象和单个对象的差异是
2.对象层次具备整体和部分,呈属性结构(如树形菜单,操作系统目录结构,公司组织架构等)

组合模式的主要角色

1.抽象构建(Component)角色,主要作用是为树叶和树枝构建声明公共接口,在透明的组合模式中抽象构建还声明和管理子类的接口,在安全模式中组合模式不声明和管理子类的接口,管理工作由树枝构建完成
2.树叶构建(Leaf)角色,是组合模式中的叶子节点对象,它没有子节点,用于实现抽象构建角色中声明的公共接口
3.树枝构建(Composite)角色,是组合模式中的分支节点对象,它有子节点,它实现了抽象构建角色中声明的公共接口,主要作用是存储和管理子部件,通常包含 Add(),Remove(),GetChild()等方法

组合模式都优缺点

优点
1.组合模式使得客户端可以一致的访问单个对象或者组合对象,无需关心处理的对象是单个对象,还是组合对象,这简化了客户端的代码
2.更容易在组合体中加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足开闭原则
缺点
1.设计复杂,客户端要花更多的时间去理清类之间的层次关系

组合模式的实现

透明组合模式

创建抽象构建

/**
 * 抽象构建  Component 透明组合模式
 * 提供树枝和树叶构建公共的接口,并实现它们的默认行为
 * 透明式组合模式还声明访问和管理子类的接口
 * 安全式组合模式将访问和管理子类的接口由树枝构建完成
 */
public abstract class Component {
    // 树枝和树叶的公共接口
    public abstract void opertation();

    // 声明管理子类的接口
    public boolean add(Component component){
        throw new UnsupportedOperationException("不支持添加操作");
    }
    public boolean remove(Component component){
        throw new UnsupportedOperationException("不支持删除操作");
    }
    public Component getChild(int index){
        throw new UnsupportedOperationException("不支持获取操作");
    }
}

创建树枝构建

/**
 * 树枝构建 Componsite
 * 是组合模式中的分支构建,它有子节点,实现类抽象构建中公共的接口
 * 主要作用是管理子部件,通常包含 add(),remove,getChild()方法等...
 */
public class Composite extends Component{
    // 保存子节点
    private List<Component> components = new ArrayList<Component>();

    private String name;
    private int level;
    public Composite(String name,int level){
        this.name = name;
        this.level = level;
    }

    @Override
    public boolean add(Component component) {
        return components.add(component);
    }

    @Override
    public boolean remove(Component component) {
        return components.remove(component);
    }

    @Override
    public Component getChild(int index) {
        return components.get(index);
    }

    @Override
    public void opertation() {
        System.out.println(this.name);
        for(Component c : this.components){
            for(int i=0;i<level;i++){
                System.out.print("   ");
            }
            c.opertation();
        }
    }
}

创建树叶构建

/**
 * 树叶构建 Leaf 是组合模式中的叶子节点,没有子节点,实现抽象构建中声明的公共接口
 */
public class Leaf extends Component{

    private String name;

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

    @Override
    public void opertation() {
        System.out.println(this.name);
    }
}

测试

    public static void main(String[] args) {

        Component root = new Composite("XXX责任有限公司",1);
        Component leaf = new Leaf("董事长");
        Component c1 = new Composite("财务部", 2);
        Component c2 = new Composite("人事部", 2);
        Component c3 = new Composite("技术部",2);
        root.add(leaf);
        root.add(c1);
        root.add(c2);
        root.add(c3);

        Component leaf1 = new Leaf("财务部主管");
        Component leaf2 = new Leaf("人事部主管");
        Component leaf3 = new Leaf("技术部主管");

        c1.add(leaf1);
        c2.add(leaf2);
        c3.add(leaf3);

        Component c4 = new Composite("技术部员工", 3);

        Component emp1 = new Leaf("技术1");
        Component emp2 = new Leaf("技术2");
        Component emp3 = new Leaf("技术3");

        c3.add(c4);

        c4.add(emp1);
        c4.add(emp2);
        c4.add(emp3);

        root.opertation();
    }

结果

XXX责任有限公司
   董事长
   财务部
      财务部主管
   人事部
      人事部主管
   技术部
      技术部主管
      技术部员工
         技术1
         技术2
         技术3

透明组合模式是把组合使用的方法放到抽象类中,不管叶子对象和树枝对象都是相同的结构,这样做的好处就是叶子节点和树枝节点对于外界没有区别,他们具有完全一致的行为接口,但因为 Leaf 叶子节点类本身并不具备 add(),remove(),getChild()功能,所以实现它是没有意义的,这是就需要使用安全组合模式,它不声明管理子类的接口,声明和管理子类的接口交给子类自己去完成

安全组合模式

创建抽象构建,只声明叶子节点和组合节点公共接口,将管理子类的接口,交个子类自己去完成

/**
 * 安全组合模式
 * 抽象构建 Component 目录类
 * 只声明叶子节点和设置节点公共的接口
 */
public abstract class Directory {
    protected String name;
    // 声明子类必须实现的构造方法
    public Directory(String name){
        this.name = name;
    }
    // 获取分支下的所有树枝节点和叶子节点
    public abstract void operation(int depth);
}

创建树枝节点,实现抽象构建的接口,并提供管理子类的方法

/**
 * 树枝节点 Composite
 * 实现抽象构建的公共接口,声明管理子类的接口
 * 一般包括 add(),remove(),getChild() 等方法
 */
public class Folder extends Directory{

    // 管理组合对象
    private List<Directory> directories = new ArrayList<Directory>();

    public Folder(String name) {
        super(name);
    }

    public boolean add(Directory directory){
        return this.directories.add(directory);
    }

    public boolean remove(Directory directory){
        return this.directories.remove(directory);
    }

    public Directory getChild(int index){
        return this.directories.get(index);
    }
    @Override
    public void operation(int depth) {
        // 输出出行结构
        for(int i=0;i<depth;i++){
            System.out.print("- ");
        }
        System.out.println(this.name);
        // 便利下一级节点
        for(Directory d : this.directories){
            d.operation(depth+1);
        }
    }
}

创建叶子节点,实现抽象构建的方法

/**
 * 叶子节点 Leaf  文件类
 * 实现抽象构建声明的公共接口
 */
public class File extends Directory{

    public File(String name) {
        super(name);
    }

    @Override
    public void operation(int depth) {
        // 输出树形结构
        for(int i=0;i<depth;i++){
            System.out.print("- ");
        }
        System.out.println(this.name);
    }
}

测试

    public static void main(String[] args) {
        Folder root = new Folder("D:\\盘");

        Folder office = new Folder("office组件");
        Directory excel = new File("excel.exe");
        Directory word = new File("word.exe");
        // 添加 office 组件
        office.add(excel);
        office.add(word);
        Directory mp3 = new File("下辈子我还记得你.mp3");

        Folder other = new Folder("高清无码...");
        Folder ont = new Folder("【一品道】");
        other.add(ont);


        Directory m1 = new File("天线宝宝第一集.mp4");
        Directory m2 = new File("天线宝宝第二集.mp4");
        Directory m3 = new File("天线宝宝第三集.mp4");
        ont.add(m1);
        ont.add(m2);
        ont.add(m3);

        // 给根目录添加节点
        root.add(office);
        root.add(mp3);
        root.add(other);

        root.operation(1);
    }

结果

- D:\盘
- - office组件
- - - excel.exe
- - - word.exe
- - 下辈子我还记得你.mp3
- - 高清无码...
- - - 【一品道】
- - - - 天线宝宝第一集.mp4
- - - - 天线宝宝第二集.mp4
- - - - 天线宝宝第三集.mp4
上一篇下一篇

猜你喜欢

热点阅读