【问题标题】:Proper way to use Composite Pattern使用复合模式的正确方法
【发布时间】:2021-04-10 19:21:37
【问题描述】:

我正在学习复合设计模式,但当我尝试从 Leaf 中添加或删除组件时,我无法理解如何同等对待每个组件(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 will do nothing here because thats the final element of the tree
    }

    @Override
    public void remove(Equipment equipment) {
        //we will 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。

【问题讨论】:

    标签: design-patterns anti-patterns


    【解决方案1】:

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

    【讨论】:

    • 您的意思是将add 和remove 方法移动到CompositeEquipment 类?
    • @Tomek 是的,add 和 remove 不应该在组件中,它们不应该是组件接口的一部分。它们只能在 Composite 中定义。这样做之后,你会发现一些设计决策是自然而然的。
    • 但是你会失去透明度,因为树叶和复合材料现在有不同的界面。这不是这个模式的全部内容。我想我正在尝试吃蛋糕并吃蛋糕。
    • 强调的是组件的方法,也就是通用接口。您需要能够轻松调用接口方法,而无需找出对象是叶子还是组合并相应地遍历树。这种模式便于调用接口方法。添加和删​​除(仅限于组合)是另一回事。你需要有一个 Composite 来添加,这是肯定的。在此处查看 Java 示例:en.wikipedia.org/wiki/Composite_pattern
    • Leaf 和 Composite 没有不同的接口。它们实现了相同的接口,但 Composite 有一些额外的方法。
    猜你喜欢
    • 1970-01-01
    • 2013-05-02
    • 2015-05-16
    • 2013-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    相关资源
    最近更新 更多