Java 装饰图案设计

Java 装饰图案设计,java,design-patterns,decorator,Java,Design Patterns,Decorator,我对模式非常陌生,我正在为一个我必须编写的程序学习装饰模式 通过在线学习,我发现了一个Decorator模式的示例(它是Java伪代码): 当我分析这个例子时,我意识到在过去我制作了一个非常相似的模式,但方式不同: import java.util.*; class Solution2 { static interface Component { void doStuff(); } static class MyComponent imp

我对模式非常陌生,我正在为一个我必须编写的程序学习装饰模式

通过在线学习,我发现了一个Decorator模式的示例(它是Java伪代码):

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

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
    }
}
import java.util.*;
类别解决方案2
{
静态接口组件
{ 
void doStuff();
}
静态类MyComponent实现组件
{
公共空间
{
// ...
}
}
静态类ComponentDecorator实现组件//这不是Decorator模式!
{ 
私有最终列表组件=新的ArrayList();
公共组件装饰器()
{
}
公共组件装饰器addComponent(组件组件)
{
此.components.add(组件);
归还这个;
}
public void removeComponent(Component Component)//装饰器可以这样做吗?
{
// ...
}
公共空间
{
对于(组件c:this.components)c.doStuff();
}
}
静态类ComponentDecorator1实现组件
{
公共组件decorator1()
{
}
私有void doExtraStuff1()
{
// ...
}
公共空间
{
doExtraStuff1();
}
}
静态类ComponentDecorator2实现组件
{
公共组件decorator2()
{
}
私有void doExtraStuff2()
{
// ...
}
公共空间
{
doExtraStuff2();
}
}
公共静态void main(字符串[]args)
{
ComponentDecorator cd=新的ComponentDecorator();
addComponent(新的MyComponent());
addComponent(新的ComponentDecorator1());
addComponent(新的ComponentDecorator2());
cd.doStuff();//执行MyComponent.doStuff、ComponentDecorator1.doExtraStuff1、ComponentDecorator2.doExtraStuff2
}
}
在我看来,第二个示例可以在使用装饰器模式的相同情况下使用,但它更灵活(通过示例,您可以删除或重新排列列表中的组件),因此我的问题是:

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

解决方案2实际上是装饰图案和复合图案的混合

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

关于使用这两种模式的更一般的答案,请参见

这是关键答案:

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

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

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

解决方案1优于解决方案2。解决方案1遵循四人帮的设计

解决方案1是

  • 简单的
  • 与解决方案2相比,更不容易出错。您必须在使用后填充列表并清除列表(您当前没有这样做)。如果在多个线程中使用同一个decorator,则必须保护代码以确保内存一致性
  • 本文档提供了VendingMachineCorator的真实示例@

    是否可以在解决方案1中添加用于删除实例的函数

    对。这是可能的。您需要在抽象装饰器和具体装饰器中添加remove函数

    public void removeStuff()
    
    您可以查看以下问题:


    因为他们做的事情不同,所以不可能分辨出哪个更好。在我看来,他们做的事情是一样的。你能说得更具体一点吗?Decorator是通过在扩展代码中包装另一个实现来扩展它的。您的解决方案只是按顺序调用不同的实现。给你。尝试使用您描述的替代方法来实现这一点,您将看到不同之处,即不要在注释plz中粘贴代码。假设基本
    Stream
    写入文件,那么在调用
    encryptedZipped.write(data)时,如何将加密和压缩的数据写入文件而不是原始数据
    ?移除装饰器的示例非常好。另一方面,“解决方案1比解决方案2好。解决方案1遵循四人帮的设计。”这不是答案。我知道解决方案1更好,我在问为什么它更好。你能回答问题1吗?
    public void removeStuff()