代码之家  ›  专栏  ›  技术社区  ›  ryeguy

如何在不强制某人重新实现所有内容的情况下实现decorator模式?

  •  1
  • ryeguy  · 技术社区  · 14 年前

    举出这个例子 Wikipedia :

    // the Window interface
    interface Window {
        public void draw(); // draws the Window
        public String getDescription(); // returns a description of the Window
    }
    
    // implementation of a simple Window without any scrollbars
    class SimpleWindow implements Window {
        public void draw() {
            // draw window
        }
    
        public String getDescription() {
            return "simple window";
        }
    }
    
    // abstract decorator class - note that it implements Window
    abstract class WindowDecorator implements Window {
        protected Window decoratedWindow; // the Window being decorated
    
        public WindowDecorator (Window decoratedWindow) {
            this.decoratedWindow = decoratedWindow;
        }
       public void draw() {
            decoratedWindow.draw();
        }
    }
    

    例如,我如何允许用户实现装饰 draw 但不是 getDescription

    在我看来,我有三个选择:

    • 将所有5个方法放在接口上。缺点是,这将迫使它们实现4个只调用父级的方法。
    • 根本不用接口。失去设计合同。

    还有其他选择吗?如果没有,以上哪一个是最好的选择?

    3 回复  |  直到 10 年前
        1
  •  1
  •   NOtherDev    14 年前

    您可以使用PHP的构造函数继承并创建一个抽象的、默认的decorator实现 AbstractWindowDecorator 抽象窗口装饰器 只重写这些方法。

    // the Window interface
    interface Window
    {
        public function draw(); // draws the Window
        public function getDescription(); // returns a description of the Window
    }
    
    // implementation of a simple Window without any scrollbars
    class SimpleWindow implements Window
    {
        public function draw()
        {
            // draw window
        }
    
        public function getDescription()
        {
            return "simple window";
        }
    }
    
    // abstract decorator class - note that it implements Window
    abstract class AbstractWindowDecorator implements Window
    {
        protected $decoratedWindow; // the Window being decorated
    
        public final function __construct ($decoratedWindow)
        {
            $this->decoratedWindow = $decoratedWindow;
        }
    
        public function draw()
        {
            return $this->decoratedWindow->draw();
        }
    
        public function getDescription()
        {
            return $this->decoratedWindow->getDescription();
        }
    }
    
    // all decorators can now
    class SampleWindowDecorator extends AbstractWindowDecorator
    {
       public function draw()
       {
           // do something other;
       }
    }
    

    抽象窗口装饰器 静止工具 Window ,因此您拥有自己的合同权利,不需要实现所有方法。而且,所有没有抽象类的decorator创建的“old way”也将符合这个模式。

    Decorator的实例化与示例中的一样:

    $w = new SimpleWindow();
    $d = new SampleWindowDecorator($w);
    echo $d->getDescription(); // "simple window"
    

    (事实上,即使没有构造函数继承,也可以这样做,但是需要为每个装饰器显式创建一个构造函数。)

        2
  •  1
  •   Patrick    14 年前

    如果你在C++中开发,你可能会使用模板。

    不是从窗口派生WindowDecorator,而是从作为模板参数给定的类派生它,如下所示:

    template <typename T>
    class WindowDecorator : public T
       {
       public:
          // Put here what you want to decorate
          // Every method not implemented here is simply forwarded to T
       };
    
    WindowDecorator<MyWindow> mywindow;
    

    当然,这也有一些假设:

    • 要修饰的实例应该与decorator一起“创建”
    • 要修饰的所有类都有一个具有相同参数的构造函数

    另一种方法是使用一个简单的“转发类”,将所有调用转发到修饰类,如下所示:

    class WindowForwarder
       {
       public:
          WindowForwarder (Window &decoratedWindow) : m_decoratedWindow(decoratedWindow) {}
          virtual void draw() {m_decoratedWindow.draw();}
          // add all forwarding methods here
       private:
          Window &m_decoratedWindow;
       };
    

        3
  •  0
  •   fabmilo    14 年前

    我看不出你的问题里有多少装饰图案。我会看到更多 Template Method Pattern

    然后将不同的逻辑指定给不同的画家。