在Decorator模式中使用其他方法

时间:2014-11-18 21:00:53

标签: design-patterns language-agnostic decorator

在GoF设计模式书的关于装饰器模式的章节中,有一个GUI控件的例子。这是C ++中的示例代码(我已经改变了一点):

class VisualComponent
{
    public:
    virtual void Draw() = 0;
};

class TextView : public VisualComponent
{
    // ...
};

class Decorator : public VisualComponent
{
    private:
    VisualComponent * component;

    public:
    Decorator(VisualComponent * c)
        : component(c)
    {}
    virtual void Draw()
    {
        component->Draw();
    }
};

class ScrollDecorator : public Decorator
{
    public:
    ScrollDecorator(VisualComponent * c)
        : Decorator(c)
    {}
    virtual void Draw()
    {
        Decorator::Draw();
    }
    void ScrollTo()   // [1]
    {
        // perform scrolling
    }
};

class BorderDecorator : public Decorator
{
    private:
    void DrawBorder()   // [2]
    {
        // draw border
    }

    public:
    BorderDecorator(VisualComponent * c)
        : Decorator(c)
    {}
    virtual void Draw()
    {
        Decorator::Draw();
        DrawBorder();
    }
};

装饰器类的要点是向对象添加新的行为/外观/等等。例如:

VisualComponent myControl = new BorderDecorator(new ScrollDecorator(new TextView)));

创建一个可滚动且具有边框的文本视图控件。添加边框对于客户端是不可见的 - 它是一种私有方法([2]),并且在Draw()接口的VisualComponent方法中调用它。

然而,在该示例中,作者还(在图中)呈现了用于滚动GUI控件([1])的方法。现在,书中没有提到任何内容,所以我不知道该方法应该做什么或应该如何表现。最重要的是,我不知道它是公开的(以及课程界面的一部分)还是私人的。

假设后一种情况,它将如何运作? VisualComponent接口定义的唯一方法是Draw()Resize(),其中没有一个真正适用于滚动控件的任务(通常通过用户单击并拖动鼠标)。我已用[3]标记了可能的调用,但我不确定他们是否正确。

假设它是前一种情况,该方法使用新的公共方法扩展了类的界面,这是我的问题的要点。客户端应该如何调用该方法?如果它不是顶级装饰器(如我们的示例中所示),则无法访问component字段,因为它是私有的。

因此,总结一下 - 装饰者类可以添加新的公共方法吗?如果是这样,这些应该怎么称呼?如果不是(在这种情况下,它们只能添加新的私有方法),这些方法是否应该以适合组件接口中定义的行为的方式扩展对象的行为(在我们的案例中VisualComponent)?例如,如果组件接口只定义了Draw()方法,那么这些新的私有方法是否只处理绘图/外观?

1 个答案:

答案 0 :(得分:0)

虽然没有什么可以阻止你通过装饰器添加新的公共方法,但它可能不是最好的解决方案。您已经正确地注意到客户端无法调用该方法,除非该对象由装饰器类型的变量引用。

this answer中,建议您使用继承或适配器模式来代替此类情况。这听起来像是避免上述缺点的合理解决方案。