【问题标题】:Decorator Pattern design装饰图案设计
【发布时间】:2016-09-28 01:23:22
【问题描述】:

我对模式很陌生,我正在为我必须编写的程序研究装饰器模式。

网上学习,发现了一个装饰器模式的例子(是Java伪代码):

class Solution1
{
    static interface Component 
    { 
        void doStuff(); 
    }

    static class MyComponent implements Component 
    {
        public void doStuff()
        {
            // ...
        }
    }

    static class ComponentDecorator implements Component  // This is the Decorator pattern.
    { 
        private final Component component;

        public ComponentDecorator(Component component) 
        {
            this.component = component;
        }

        public void doStuff()
        {
            this.component.doStuff();
        }
    }

    static class ComponentDecorator1 extends ComponentDecorator 
    {
        public ComponentDecorator1(Component component) 
        {
            super(component);
        }

        private void doExtraStuff1()
        {
            // ...
        }

        public void doStuff()
        {
            super.doStuff();
            doExtraStuff1();
        }
    }

    static class ComponentDecorator2 extends ComponentDecorator 
    {
        public ComponentDecorator2(Component component) 
        {
            super(component);
        }

        private void doExtraStuff2()
        {
            // ...
        }

        public void doStuff()
        {
            super.doStuff();
            doExtraStuff2();
        }
    }

    public static void main(String[] args)
    {
        MyComponent         c   = new MyComponent();
        ComponentDecorator1 cd1 = new ComponentDecorator1(c);
        ComponentDecorator2 cd2 = new ComponentDecorator2(cd1);

        cd2.doStuff(); // Executes Component.doStuff, ComponentDecorator1.doExtraStuff1, ComponentDecorator2.doExtraStuff2
    }
};

当我分析这个例子时,我意识到过去我做了一个非常相似但方式不同的模式:

import java.util.*;

class Solution2
{
    static interface Component 
    { 
        void doStuff(); 
    }

    static class MyComponent implements Component 
    {
        public void doStuff()
        {
            // ...
        }
    }

    static class ComponentDecorator implements Component  // This is NOT the Decorator pattern!
    { 
        private final List<Component> components = new ArrayList<Component>();

        public ComponentDecorator() 
        {
        }

        public ComponentDecorator addComponent(Component component)
        {
            this.components.add(component);
            return this;
        }

        public void removeComponent(Component component) // Can Decorator do this?
        {
            // ...
        }

        public void doStuff()
        {
            for(Component c : this.components) c.doStuff();
        }
    }

    static class ComponentDecorator1 implements Component 
    {
        public ComponentDecorator1() 
        {
        }

        private void doExtraStuff1()
        {
            // ...
        }

        public void doStuff()
        {
            doExtraStuff1();
        }
    }

    static class ComponentDecorator2 implements Component 
    {
        public ComponentDecorator2() 
        {
        }

        private void doExtraStuff2()
        {
            // ...
        }

        public void doStuff()
        {
            doExtraStuff2();
        }
    }

    public static void main(String[] args)
    {
        ComponentDecorator cd  = new ComponentDecorator();
        cd.addComponent(new MyComponent());
        cd.addComponent(new ComponentDecorator1());
        cd.addComponent(new ComponentDecorator2());

        cd.doStuff(); // Executes MyComponent.doStuff, ComponentDecorator1.doExtraStuff1, ComponentDecorator2.doExtraStuff2
    }
}

在我看来,第二个示例可以在可以使用装饰器模式的相同情况下使用,但它更灵活(例如,您可以删除或重新排序列表中的组件),所以我的问题:

  • 解决方案 1(正确的装饰器模式)是否优于解决方案 2?为什么?
  • 是否可以在解决方案 1 中添加删除实例的功能?
  • 是否可以在解决方案 1 中添加用于重新排序实例的函数?

【问题讨论】:

  • 无法分辨哪个更好,因为他们做的事情不同。
  • 在我看来他们做同样的事情。你能说得更具体点吗?
  • 装饰器是关于通过在扩展代码中包装来扩展另一个实现。您的解决方案只是按顺序调用不同的实现。这是my answer on decorator。尝试使用您描述的替代方法来实现它,您会看到差异
  • 请不要在 cmets 中粘贴代码。
  • 假设基本的Stream 写入文件,当您调用encryptedZipped.write(data) 时,这将如何将加密和压缩数据而不是原始数据写入文件?

标签: java design-patterns decorator


【解决方案1】:

解决方案 2 实际上是装饰器模式和复合模式的混合。

如果你想要的只是添加行为,我认为解决方案 1 比解决方案 2 更好,如果你还需要使用多个对象作为一个对象,使用解决方案 1 + 复合模式会更好。

作为关于使用这两种模式的更一般的答案,请参阅 Difference between the Composite Pattern and Decorator Pattern?

这是关键答案:

复合模式允许您以允许外部代码将整个结构视为单个实体的方式构建层次结构(例如元素树)。因此,叶实体的接口与复合实体的实体完全相同。所以本质是复合结构中的所有元素都具有相同的接口,即使有些是叶节点而另一些是整个结构。用户界面通常使用这种方法来实现轻松的可组合性。

http://en.wikipedia.org/wiki/Composite_pattern

装饰器模式允许一个实体完全包含另一个实体,以便使用装饰器看起来与包含的实体相同。这允许装饰器在不改变实体外观的情况下修改它所封装的任何内容的行为和/或内容。例如,您可以使用装饰器在包含元素的使用情况下添加日志输出,而不会更改包含元素的任何行为。

http://en.wikipedia.org/wiki/Decorator_pattern

【讨论】:

    【解决方案2】:

    解决方案 1(正确的装饰器模式)是否比解决方案 2 更好?为什么?

    解决方案 1 比解决方案 2 更好。解决方案 1 遵循 Gang of 4 设计。

    解决方案1是

    1. 简单
    2. 与解决方案 2 相比,更不容易出错。您必须在使用后填充列表并清除列表(您目前没有这样做)。如果您在多个线程中使用相同的装饰器,则必须保护代码以确保内存一致性。

    VendingMachineDecorator 的真实世界示例可在此文档中找到@

    When to Use the Decorator Pattern?

    是否可以在方案一中添加移除实例的功能?

    是的。这是可能的。您可以在抽象装饰器和具体装饰器中添加删除功能。

    public void removeStuff()
    

    您可以查看以下 SE 问题:

    How to remove decorated object from Decorator Pattern in Java

    Can you remove a decorator?

    【讨论】:

    • 移除装饰器的例子非常好。另一方面,“解决方案 1 比解决方案 2 更好。解决方案 1 遵循 Gang of 4 设计。”不是回答。我知道解决方案 1 更好,我在问为什么它更好。您能回答问题 1 吗?
    猜你喜欢
    • 1970-01-01
    • 2015-07-25
    • 2019-02-27
    • 2012-04-23
    • 2016-05-08
    • 2012-01-17
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多