使用装饰器模式时,是否可以在具体的装饰器对象中添加新的装饰器

When using the decorator pattern, can I add new decorators within a concrete decorator object?

本文关键字:对象 添加 模式 是否      更新时间:2023-10-16

示例:

class Display
{
public:
    virtual void display() = 0;
};
class PageDisplay : public Display
{
public:
    void display() { /* ... */ }
};
class DisplayDecorator : public Display
{
public:
    DisplayDecorator(Display* display) : m_display(display) {}
    virtual void display() { m_display->display(); }
private:
    Display* m_display;
};
class BorderDecorator : public DisplayDecorator
{
public:
    BorderDecorator(Display* display) : DisplayDecorator(display) {}
    virtual void display() { DisplayDecorator::display(); /* do border stuff here ... */ }
};
int main()
{
    Display* pageDisp = new BorderDecorator(new PageDisplay());
    pageDisp->display();
}

因此,这是装饰器模式的一个相当基本的实现。但是,例如,假设我想从边界装饰器具体类中添加一个额外的装饰器。因此,BorderDecorator::d isplay函数现在看起来像这样:

virtual void display()
{ 
    /*
    I need to add a decorator that will display a slider bar at the side of the screen, 
    and that will wrap the PageDisplay decorator so that it will run before the page display.
    Is there a clean way to get my base class' m_display pointer so that I can do something like this:
    */
    m_display = new SliderDecorator(m_display);
    DisplayDecorator::display();
    /* do border stuff here ... */
}

我也知道,在这个例子中,我真的只想从客户端函数中应用 SliderDecorator(在本例中是主要的)。在我的头顶上,我无法想出一个很好的例子来说明为什么需要从具体的装饰器对象中添加额外的装饰器(除了我正在做的事情),但请耐心等待;我这样做确实有充分的理由。我也知道我可以保护抽象装饰器对象(在本例中m_display)中的抽象基类指针而不是私有,然后像我在示例中所做的那样从具体的装饰器对象中添加其他装饰器,但这似乎是一个坏主意,因为它分解了数据封装, 现在装饰者可以不恰当地与他们装饰的对象进行交互。话虽如此,这是我唯一的选择吗?在混凝土装饰器的"装饰"功能中,有没有更好的方法将复合装饰器与另一个装饰器包裹起来,然后像往常一样继续?

事情是这样的。客户应该知道要应用哪些装饰器。将此逻辑推送到装饰器内部是没有意义的,因为当客户端调用 BorderDecorator 时,它只期望边框,而不是带有滑块的边框。在客户端代码中,如果要链接多个需要能够动态指定的修饰器,则可以使用责任链模式。

当然,为什么不呢?您本质上是对添加的装饰器进行专用化,或者使用实用程序类/方法来构造常用的装饰器组合。

听起来像是代码的良好整合。继续前进。