使用Composite Pattern的正确方法

时间:2016-07-10 10:22:01

标签: design-patterns anti-patterns gang-of-four

我正在学习复合设计模式,当我尝试在Leaf I中添加或删除组件时,我无法理解如何对每个组件进行相同的处理(Leaf和Composite)应该得到一个错误(或什么都不应该发生)。这对我来说似乎是一种可怕的设计,因为它违反了继承规则来对待对象。唯一的方法是以某种方式区分Composite和Leaf,并始终注意我正在使用的是什么。但这让我回到原来的问题......

组件:

public abstract class Equipment {
    private String name;

    protected Equipment(String name){
        this.name = name;
    }

    public String name(){
        return name;
    }


    public abstract int power();
    public abstract double netPrice();
    public abstract double discountPrice();

    public abstract void add(Equipment equipment);
    public abstract void remove(Equipment equipment);

    public Iterable<Equipment> createIterator(){
        return Collections.emptyList();
    }
}

组合:

public abstract class CompositeEquipment extends Equipment{
    private final List<Equipment> elements;

    protected CompositeEquipment(String name) {
        super(name);
        elements = new LinkedList<>();
    }

    @Override
    public double netPrice() {
        Iterable<Equipment> iter = createIterator();
        double total = 0;

        for (Iterator<Equipment> i = iter.iterator(); i.hasNext() ;) {
            Equipment next = i.next();
            total += next.netPrice();
        }

        return total;
    }

    @Override
    public Iterable<Equipment> createIterator() {
        return elements;
    }

    @Override
    public void remove(Equipment equipment){
        elements.remove(equipment);
    }

    @Override
    public void add(Equipment equipment){
        elements.add(equipment);
    }

}

public class FloppyDisk extends Equipment{

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

    @Override
    public int power() {
        return 1;
    }

    @Override
    public double netPrice() {
        return 3;
    }

    @Override
    public double discountPrice() {
        return 2.2;
    }

    @Override
    public void add(Equipment equipment) {
        //we well do nothing here because thats the final element of the tree
    }

    @Override
    public void remove(Equipment equipment) {
        //we well do nothing here because thats the final element of the tree
    }

}

我看到的问题:

public void extendTheTree(Equipment equipment){
    equipment.add( new CompositeWithLeafs() );  //lets hope it is a Composite not a Leaf!!!
}

那么我应该如何使用这种模式呢?或者在什么样的场景中?我看到的唯一解决方案是摆脱Leaf概念并仅使用Composits。

1 个答案:

答案 0 :(得分:2)

你误解的根源在于你采用了对Leaf有意义的方法和对Composite有意义的方法,并将这些方法的联合放在public abstract class Equipment中,即你的组件。这样,你最终得到了Leaf和Composite的共同祖先,其中一部分祖先对Leaf没有意义。我说的是addremove方法,它们对Leaf没有意义,因此首先不应该成为Component的一部分。是否应该使用抽象类或接口来表示组件是另一个问题,您可以在此站点中找到完美的分析。但事实是Component应该包含Leaf的方法和Composite的方法的交集,这是一组可以在对象上使用的方法,而不知道它是Leaf还是Composite。更正式地说,Component应该定义应该由Leaf和Composite实现的公共接口。如果你这样做,你会发现你永远不会add到Leaf,因为Component接口不应该有这样的方法来覆盖,而Leaf也不应该有这样的方法。无论好坏,你只能add到你认识的是复合材料。