首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >正确使用组合模式

正确使用组合模式
EN

Stack Overflow用户
提问于 2016-07-10 10:22:00
回答 2查看 1.1K关注 0票数 1

我正在学习复合设计模式,我不明白当我试图从中添加或删除组件时,我如何才能将每个组件处理为相同的(叶和复合)(否则什么都不会发生)。对我来说,这似乎是一个可怕的设计,因为它违反了继承的规则,将对象处理相同。唯一的办法是从某种程度上区分复合和叶子,并始终意识到我在做什么。但这让我回到原来的问题..。

组件:

代码语言:javascript
复制
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();
    }
}

复合材料:

代码语言:javascript
复制
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);
    }
    
}

叶:

代码语言:javascript
复制
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
    }
    
}

我看到的问题:

代码语言:javascript
复制
public void extendTheTree(Equipment equipment){
    equipment.add( new CompositeWithLeafs() );  //lets hope it is a Composite not a Leaf!!!
}

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

EN

回答 2

Stack Overflow用户

发布于 2016-07-10 12:12:27

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

票数 3
EN

Stack Overflow用户

发布于 2022-10-09 19:59:36

来自维基百科

有两个设计变体用于定义和实现与子组件相关的操作,例如向容器中添加/移除子组件(add(子)/remove(GetChild))和访问子组件(getChild()): 一致性设计:在组件接口中定义了与子相关的操作。这使客户端能够统一地处理叶子和Composite对象。但是类型安全性会丢失,因为客户端可以对叶子对象执行与子相关的操作。 类型安全设计:仅在复合类中定义与子级相关的操作。客户端必须以不同的方式对待叶子和组合对象。但是由于客户端不能对叶子对象执行与子相关的操作,所以获得了类型安全性。 组合设计模式强调的是统一性,而不是类型安全性。

在您的示例中,您选择通过在组件(设备)抽象类中添加与子相关的操作(即添加/删除)来设计一致性,这样您就失去了类型安全性,因为您的客户端可以调用叶子(FloppyDisk)对象上的添加/删除方法。

关于每种设计的优点和缺点的有趣讨论,以及何时选择一种设计而不是另一种设计,都可以找到这里

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38290865

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档