Java:装饰器模式 - 对主要抽象类的引用

时间:2017-10-30 15:37:37

标签: java design-patterns decorator

我已阅读有关装饰器模式的this article,我有一个问题。

此类仅来自抽象类SandWichDecorator

public class CheeseDecorator extends SandWichDecorator{
    Sandwich currentSandwich;

    public CheeseDecorator(Sandwich sw){
        currentSandwich = sw;
    }

    @Override
    public String getDescription(){
        return currentSandwich.getDescription() + ", Cheese";
    }
    @Override
    public BigDecimal price() {
        return currentSandwich.price().add(new BigDecimal("0.50"));
    }
}

为什么在abstract类中引用SandwichSandwich currentSandwich; CheeseDecorator

将它放入抽象类SandWichDecorator会更容易吗? 每个扩展SandWichDecorator的班级都会自动获得参考。

3 个答案:

答案 0 :(得分:2)

你的建议很好恕我直言。 它也匹配GOF原件: decorator

在讨论模式时,重要的是要记住变体是可以接受的,没有"模式警察"谴责你的每一个小小的偏差(只要考虑得很好)......如果是我,我将一些文章的AbstractClasses改为接口,我仍然相信我的设计意图清晰可接受。

也许你可以在评论中询问作者(虽然它是一篇旧帖子)。如果我不得不猜测,我会假设作者想要在" currentSandwich"中保留一些灵活性。声明/位置(比如从一个threadLocal中取出它,组合两个sandwitches等),但是这样的“创造力”和#39;会破坏一般性和模块性 - 即将几个装饰者包裹在另一个上面的自由。我更喜欢我的装饰师坚持一个明确定义的" currentSandwitch",在这种情况下采用你的想法是好的。

答案 1 :(得分:2)

是的,你是对的。您可以在current中使用SandwichDecorator三明治,如下所示:

public abstract class SandwichDecorator implements Sandwitch {

    protected final Sandwitch current;

    public SandwichDecorator(Sandwitch current) {
        this.current = current;
    }

}

但实际上,你甚至不需要SandwichDecorator课程。您可以拥有一个接口Sandwich并实现它。仅仅因为持有"装饰"而不是一个抽象的课程是不值得的。参考:

interface Sandwich {
    String description();
    float price();
}

class BasicSandwich implements Sandwich {
    @Override
    public String description() {
        return "Sandwich";
    }    
    @Override
    public float price() {
        return 4f;
    }    
}

class CheeseSandwich implements Sandwich {   
    private final Sandwich origin;
    public CheeseSandwich(Sandwich origin) {
        this.origin = origin;
    }
    @Override
    public String description() {
        return origin.description() + " , Cheese";
    }    
    @Override
    public float price() {
        return origin.price() + 1f;
    }   
}

//More implementations of Sandwich

你可以像这样使用它:

Sandwich completeSandwich = new CheeseSandwich(new BasicSandwich());

使用接口进行设计比使用抽象类更灵活。每次你写extends时,一只小猫都会死。

答案 2 :(得分:2)

模式的本质是允许静态或动态地将新功能/改变的行为添加到对象,而不会影响同一类对象的行为。

您利用多态来实现这一目标。基本抽象类或接口提供要作为输入和输出传递的对象的“类别”以进行装饰。

这只是作者选择展示模式的方式,我同意你的看法,它可能更精简。

Hector提供的示例(没有SandwichDecorator类)在我看来更好地实现了该示例的模式。