YAZONG 我的开源

设计模式(十八)结构型模式(对象结构型模式)组合/组成模式-COMPOSITE

 
0 评论0 浏览

2、18组合模式

定义

组合模式也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系,其定义如下:将对象组合成树形结构以表示”部分-整体”的层次结构,(统一处理)使得用户对单个对象和组合对象的使用具有一致性(忽略对象组合和个别对象之间的差别)。

组合模式有两种不同的实现:透明模式和安全模式。

安全模式

类图

image.png

1)Component抽象构件角色

定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性。

2)Leaf叶子构件

叶子对象,其下再也没有其他的分支,也就是遍历的最小单位。

3)Composite树枝构件

树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构。

这个构件/角色定义构件的行为,而这样的构件具有子节点。

案例

import java.util.ArrayList;

 

/**

 * 场景类

 * TODO 安全模式的组合模式,把树枝节点和树叶节点彻底分开,树枝节点单独拥有用来组合的方法.

 * TODO 下述树叶和树枝的定义直接使用了实现类,这在面向接口编程中很不恰当,与依赖倒置原则冲突,限制了接口的影响范围.

 */

public class Client1 {

    public static void main(String[] args) {

        //创建一个根节点

        Composite root = new Composite();

        root.doSomething();

        //创建一个树枝构件

        Composite branch = new Composite();

        //创建一个叶子节点

        Leaf leaf = new Leaf();

        //建立整体

        root.add(branch);

        branch.add(leaf);

        display(root);

    }

    //通过递归遍历树

    public static void display(Composite root){

        for(Component component : root.getChildren()){

            if(component instanceof Leaf){

                component.doSomething();

            }else{

                display((Composite)component);

            }

        }

    }

}

 

/**

 * 抽象构件

 */

abstract class Component{

    //个体和整体都具有的共享

    public void doSomething(){

        //业务逻辑

        System.out.println("....");

    }

}

 

/**

 * 树枝构件

 * TODO 组合模式的重点就在树枝结构

 */

class Composite extends Component{

    //构件容器

    private ArrayList<Component> componentArrayList = new ArrayList<>();

    //增加一个叶子节点或树枝构件

    public void add(Component component){

        this.componentArrayList.add(component);

    }

    //删除一个叶子节点或树枝构件

    public void remove(Component component){

        this.componentArrayList.remove(component);

    }

    //获得分支下的所有叶子构件和树枝构件

    public ArrayList<Component> getChildren(){

        return this.componentArrayList;

    }

}

 

/**

 * 树叶构件

 * TODO 树叶节点是没有子下级对象的对象,定义参加组合的原始对象行为.

 */

class Leaf extends Component{

    //可以重写父类方法

    /*@Override

    public void doSomething() {

        super.doSomething();

    }*/

}

透明模式

类图

image.png

案例

import java.util.ArrayList;

 

/**

 * 场景类

 * TODO 透明模式:把用来组合使用的方法放到抽象类中.不管是叶子对象还是树枝对象都有相同的结构,如果处理不当,那么会在运行期间出现问题.

 * TODO 仅仅在遍历时不用进行牵制的类型转换了,其他的组装跟"安全模式"相比没有任何变化.好处是基本遵循了依赖倒置原则,方便系统进行扩展.

 */

public class Client2 {

    public static void main(String[] args) {

        //创建一个根节点

        Composite root = new Composite();

        root.doSomething();

        //创建一个树枝构件

        Composite branch = new Composite();

        //创建一个叶子节点

        Leaf leaf = new Leaf();

        //建立整体

        root.add(branch);

        branch.add(leaf);

        display(root);

    }

    //通过递归遍历树

    public static void display(Component root){

        for(Component component : root.getChildren()){

            //叶子节点

            if(component instanceof Leaf){

                component.doSomething();

            }

            //树枝节点

            else{

                display(component);

            }

        }

    }

}

 

/**

 * 抽象构件定义了树枝节点和树叶节点都必须具有的方法和属性

 */

abstract class Component{

    //个体和整体都有的共享

    public void doSomething(){

        //编写业务逻辑

        System.out.println("----");

    }

    //增加一个叶子构件或树枝构件

    public abstract void add(Component component);

    //删除一个叶子构件或树枝构件

    public abstract void remove(Component component);

    //获得分支下的所有叶子构件和树枝构件

    public abstract ArrayList<Component> getChildren();

}

/**

 * 树枝构件

 * TODO 组合模式的重点就在树枝结构

 */

class Composite extends Component{

    //构件容器

    private ArrayList<Component> componentArrayList = new ArrayList<>();

    //增加一个叶子节点或树枝构件

    @Override

    public void add(Component component){

        this.componentArrayList.add(component);

    }

    //删除一个叶子节点或树枝构件

    @Override

    public void remove(Component component){

        this.componentArrayList.remove(component);

    }

    //获得分支下的所有叶子构件和树枝构件

    @Override

    public ArrayList<Component> getChildren(){

        return this.componentArrayList;

    }

}

 

/**

 * 树叶节点

 * TODO 空方法直接抛"不支持请求"的异常即可

 * TODO @Deprecated注解就是在编译期间高速调用者,在调用此方法时会出现错误.在运行期间也会抛出异常,"该方法已经失效".

 */

class Leaf extends Component{

    @Deprecated

    @Override

    public void add(Component component) {

        throw new UnsupportedOperationException();

    }

    @Deprecated

    @Override

    public void remove(Component component) {

        throw new UnsupportedOperationException();

    }

    @Deprecated

    @Override

    public ArrayList<Component> getChildren() {

        throw new UnsupportedOperationException();

    }

}

遍历

类图

image.png

案例

import java.util.ArrayList;

 

/**

 * 场景类

 */

public class Client3 {

    public static void main(String[] args) {

 

    }

}

/**

 * 抽象构件

 */

abstract class Corp{

    //公司每个人都有名称

    private String name = "";

    //公司每个人都有职位

    private String position = "";

    //公司每个人都有薪水

    private int salary = 0;

    //父节点是谁

    private Corp parent = null;

 

    public Corp(String name, String position, int salary) {

        this.name = name;

        this.position = position;

        this.salary = salary;

    }

 

    //获得员工信息

    public String getInfo() {

        return "Corp{" +

                "name='" + name + '\'' +

                ", position='" + position + '\'' +

                ", salary=" + salary +

                '}';

    }

    //设置父节点

    protected void setParent(Corp _parent){

        this.parent = _parent;

    }

    //得到父节点

    public Corp getParent(){

        return this.parent;

    }

}

class Branch extends Corp{

    //下属列表

    private ArrayList<Corp> list = new ArrayList<>();

    //构造函数是必须的

    public Branch(String name, String position, int salary) {

        super(name, position, salary);

    }

    //增加一个下属

    public void add(Corp corp){

        //设置父节点

        this.setParent(this);

        this.list.add(corp);

    }

    //下属列表

    public ArrayList<Corp> getList() {

        return this.list;

    }

}

组合迭代器

类图

image.png

案例

import java.util.ArrayList;

import java.util.Iterator;

import java.util.Stack;

 

/**

 * 场景类

 */

public class Client4 {

    public static void main(String[] args) {

 

    }

}

 

/**

 * 抽象构件(多余的方法略)

 */

abstract class MenuComponent{

    protected abstract Iterator createIterator();

}

class Menu extends MenuComponent{

    private ArrayList<MenuComponent> menuComponents = new ArrayList<>();

    @Override

    public Iterator createIterator(){

        return new CompositeIterator(menuComponents.iterator());

    }

}

class MenuItem extends MenuComponent{

    @Override

    public Iterator createIterator(){

        return new NullIterator();

    }

}

 

/**

 * 外部迭代器,所以有许多需要追踪的事情.

 */

class CompositeIterator implements Iterator{

 

    private Stack stack = new Stack();

 

    public CompositeIterator(Iterator iterator) {

        this.stack.push(iterator);

    }

 

    @Override

    public Object next() {

        if(hasNext()){

            Iterator iterator = (Iterator)stack.peek();

            //如果还有下一个元素,那么从堆栈中取出目前的迭代器,然后取得它的下一个元素.

            MenuComponent component = (MenuComponent)iterator.next();

            if(component instanceof Menu){

                //丢进堆栈中

                stack.push(component.createIterator());

            }

            return component;

        }

        return null;

    }

 

    @Override

    public boolean hasNext() {

        if(stack.isEmpty()){

            return false;

        }else{

            //检查堆栈是否被清空

            Iterator iterator = (Iterator)stack.peek();

            if(!iterator.hasNext()){

                //从堆栈的顶层中取出迭代器

                stack.pop();

                return hasNext();

            }else{

                return true;

            }

        }

    }

    @Override

    public void remove() {

        throw new UnsupportedOperationException();

    }

}

 

/**

 * 空迭代器

 * TODO 这是空对象"设计模式"的另一个例子.

 */

class NullIterator implements Iterator{

    @Override

    public boolean hasNext() {

        return false;

    }

 

    @Override

    public Object next() {

        return null;

    }

 

    @Override

    public void remove() {

        throw new UnsupportedOperationException();

    }

}

特性

1)高层模块调用简单

一棵树形机构中的所有节点都是Component,局部和整体对调用者来说没有任何区别,也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。

2)节点自由增加

使用了组合模式后,如果想增加一个树枝节点、树叶节点都很容易,只要找到它的父节点就成,非常容易扩展,符合开闭原则,对以后的维护非常有利。

使用场景

1)维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理。

image.png

上述例子中是组合模式的真实引用,它依靠了关系数据库的非对象存储功能,非常方便地保存了一个树形结构。

2)从一个整体中能够独立出部分模块或功能的场景。

3)现在的页面结构:上面系统LOGO、下面两部分,左边是导航菜单、右边是展示区。

4)XML,用JDOM或DOM4J来解析。

5)如果组合结构很复杂,或者遍历的代价太高,那么实现组合节点的缓存就很有帮助。比如说,如果要不断地遍历一个组合,而且它的每一个子节点都需要进行某些计算,那就应该使用缓存来临时保存结果,省去遍历的开支。

注意事项

1)只要是树形结构,就要考虑使用组合模式。只要是体现局部和整体的关系的时候,而且这种关系还可能比较深,就要考虑使用组合模式。

2)当发现需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。

3)组合模式定义了包含基本对象和组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了。

4)组合模式让客户可以一致地使用组合结构和单个对象,二者对于外界来说没有区别,它们具备完全一致的行为接口。

5)在实现组合模式时,有许多设计上的折中。要根据需要平衡透明性和安全性。

6)应该努力让一个类只有一个责任。


标题:设计模式(十八)结构型模式(对象结构型模式)组合/组成模式-COMPOSITE
作者:yazong
地址:https://blog.llyweb.com/articles/2020/08/17/1597596584843.html