设计模式系列(结构型模式)之四 组合模式

组合模式

将对象组合成树形结构以表示“部分-整体”的层次结构,使客户端对单个对象和组合对象保持一致的方式处理。

适用于:
客户端可以忽略组合对象与单个对象的差异;
处理树形结构数据。

优点:
层次清晰;
客户端不必关系层次差异,方便控制;
符合开闭原则。

缺点:
树形处理较为复杂。

组合模式分为透明式的组合模式和安全式的组合模式。
(1) 透明方式:在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。
(2) 安全方式:在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。

主要场景:
1.在需要表示一个对象整体与部分的层次结构的场合。
2.要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合

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

举个去耐克店买衣服的例子:
1.定义一个抽象构件物品,里面有显示和计算两个抽象方法

public abstract class Article {
    
    
    public abstract void show();
    public abstract float calculation();

}

2.创建树叶构件商品Goods,继承自抽象构件物品Article ,里面有商品的名字,数量,单价等基本属性,并重新继承的抽象方法

public class Goods extends Article{
    
    
    private String name;
    private int count;
    private float price;

    public Goods(String name, int count, float price) {
    
    
        this.name = name;
        this.count = count;
        this.price = price;
    }

    @Override
    public void show() {
    
    
        System.out.println(name+"(数量:"+count+",单价:"+price+"元)");
    }

    @Override
    public float calculation() {
    
    
        return count*price;
    }
}

3.创建树枝构件,袋子Bag,继承自抽象构件物品Article ,通过用ArrayList数组来实现存储和管理树叶构件

public class Bag extends Article{
    
    
    private String name;
    private ArrayList<Article> bags=new ArrayList();
    public Bag(String name){
    
    
        this.name=name;
    }
    public void add(Article a) {
    
    
        bags.add(a);
    }
    public void remove(Article a) {
    
    
        bags.remove(a);
    }
    public Article getChild(int i) {
    
    
       return bags.get(i);
    }
    @Override
    public void show() {
    
    
        for(Object obj:bags){
    
    
            ((Article)obj).show();
        }

    }
    @Override
    public float calculation() {
    
    
        float p=0;
        for(Object obj:bags){
    
    
            p+=((Article)obj).calculation();
        }
        return p;
    }
}

4.测试输出

public class Test {
    
    
    public static void main(String[]args){
    
    
        float p=0;
        Bag bigBag,mediumBag,smallBag;
        Goods gs;
        bigBag=new Bag("大袋子");
        mediumBag=new Bag("中袋子");
        smallBag=new Bag("小袋子");
        gs=new Goods("耐克鞋",1,500);
        mediumBag.add(gs);
        gs=new Goods("上衣",2,100);
        mediumBag.add(gs);
        gs=new Goods("裤子",2,200);
        mediumBag.add(gs);
        gs=new Goods("袜子",3,10);
        smallBag.add(gs);
        System.out.println("您选择的商品有:");
        bigBag.add(mediumBag);
        bigBag.add(smallBag);
        bigBag.show();
        p=bigBag.calculation();
        System.out.println("总价:"+p);
    }
}
/*
您选择的商品有:
耐克鞋(数量:1,单价:500.0元)
上衣(数量:2,单价:100.0元)
裤子(数量:2,单价:200.0元)
袜子(数量:3,单价:10.0元)
总价:1130.0元
*/

通过上面的输出看出,这是一个安全方式的组合模式,抽象构件和树叶构件没有对子对象的管理方法,下一篇讲讲桥接模式

猜你喜欢

转载自blog.csdn.net/qq_40136782/article/details/108320864