Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用列表而不是装饰器模式?_Java_List_Oop_Design Patterns_Decorator - Fatal编程技术网

Java 使用列表而不是装饰器模式?

Java 使用列表而不是装饰器模式?,java,list,oop,design-patterns,decorator,Java,List,Oop,Design Patterns,Decorator,来自“Head First:Design Patterns”一书的一个装饰模式用例让我产生了这个问题。我试着写下来: 这是一个咖啡店系统,有一些咖啡和很多调味品 你可以把他们(额外的费用),你需要能够订购 并收取顾客想要的任何调味品的咖啡费用,以及 避免发生完全的混乱(例如,布尔人跟踪 调味品)使用装饰图案。我们有一种抽象饮料 类别,每种咖啡作为具体成分和每种调味品 作为包装饮料的混凝土装饰工,如下所示: 因此,我们有以下流程返回咖啡成本: 我的问题是:为什么不用列表而不是装饰器来实现呢?我

来自“Head First:Design Patterns”一书的一个装饰模式用例让我产生了这个问题。我试着写下来:

这是一个咖啡店系统,有一些咖啡和很多调味品 你可以把他们(额外的费用),你需要能够订购 并收取顾客想要的任何调味品的咖啡费用,以及 避免发生完全的混乱(例如,布尔人跟踪 调味品)使用装饰图案。我们有一种抽象饮料 类别,每种咖啡作为具体成分和每种调味品 作为包装饮料的混凝土装饰工,如下所示:

因此,我们有以下流程返回咖啡成本:

我的问题是:为什么不用列表而不是装饰器来实现呢?我们可以在每种饮料中列出一份调味品清单,并通过反复查看清单来计算成本。要订购咖啡,我们只需将其实例化一次并添加所需的调味品,避免声明如下:

// Using second image example
Beverage beverage = new DarkRoast(beverage);
beverage = new Mocha(beverage);
beverage = new Whip(beverage);

除此之外,一旦我们不再有装饰师包装咖啡,我们将有更大的灵活性,比如对不含调味品的咖啡给予折扣。这是一个经过长期研究的问题,我知道我遗漏了什么,或者可能是我弄错了什么,所以如果你对此有任何想法,我很想知道并进一步讨论。

你应该区分数据和行为

装饰者是一个处理非常具体问题的间接层。数据(在类型、契约、协议等方面)保持不变,但您在实现方面获得了更大的灵活性。有了decorator,您可以重用现有的功能并开始添加更改—结合适当的适配器,您基本上可以慢慢地开始从pone API迁移到另一个API并保持兼容


列表应仅负责以特定方式提供对所含数据的访问。对数据执行任务/处理列表中包含的数据应按不同职责的功能/对象/类别来完成。

您所说的是计算饮料总成本的一种方法。更一般地说,您提出了另一种合并和执行Decorator模式假定的每个派生对象的主要行为的方法,方法是将它们添加到一个列表中。而且它也不是一种面向对象的方法

但它的初衷是从更广泛的角度出发的。它是动态地向对象添加扩展功能。这意味着我有一些对象
O1
&我希望它将其转换为另一个具有扩展功能的对象
O2
&但这两个对象可以互换


因此,它是关于我们如何管理对象的演化。希望你有这个想法

Decorator
模式是关于在运行时用附加功能装饰(增强)对象

假设您已经有一个类,让我们将其称为class
a
,它实现了一个接口
IA
。现在,如果需要添加一个附加功能,我们希望它有一个方法,
someAlignFeatureToA()
,这在
a
中没有。现在您可以选择扩展类
A
。另一种方法是
组合
,应该优先于
继承
。您可以将类
A
的对象包装到另一个类
B
中,实现与
A
相同的
接口,即
IA
。通过这种方式,对于客户机代码,很容易接受类B的对象,因为它与类A具有相同的接口(假设代码编写良好,这取决于抽象(接口
IA
),而不是具体的类,如类
A

这样继承链就不会太长,您可以在运行时轻松添加其他特性

现在来回答您的问题:是的,在您的问题中的示例中,列表更合适,但我觉得作者打算用一个简单的示例来解释装饰图案的用法。 假设咖啡由牛奶、咖啡混合物和糖组成。咖啡混合物进一步由更小的成分组成。这里的解决方案类似于复合模式


装饰模式是基于行为增强的设计模式。Java IO streams使用此方法,其中行为(方法实现)由装饰类增强(一个流被另一个流包装以增强前一个流)

免责声明:我使用的术语和代码片段取自

正如您所注意到的,有两种可能的设计来“装饰”对象。这两种方法可以实现相同的功能,主要区别在于使用环境

垂直装饰器 这是实现装饰器最常用的方法。我几乎完全用这种方式实现我的装饰器,因为我发现它更“自然”和简单。当装饰器的数量不太多(多少取决于程序员的解释)时,它是合适的。 当某些对象需要动态扩展时,它也非常适合:当实例化时不知道需要哪些装饰器时

水平装饰器 在非常罕见的情况下(当装饰器的数量开始增长时),我会选择在列表式结构中“展平”装饰器。这样做的优点是简化了代码的读取,但缺点是在运行时失去了灵活性:在创建对象时需要知道要应用哪个装饰器(这在不变性的上下文中尤其如此,我试图培养不变性),因此这可能是不可行的,具体取决于应用程序

最后,这只是一个设计决定,你没有
Numbers numbers = new Sorted(
  new Unique(
    new Odds(
      new Positive(
        new ArrayNumbers(
          new Integer[] {
            -1, 78, 4, -34, 98, 4,
          }
        )
      )
    )
  )
);
Numbers numbers = new Modified(
  new ArrayNumbers(
    new Integer[] {
      -1, 78, 4, -34, 98, 4,
    }
  ),
  new Diff[] {
    new Positive(),
    new Odds(),
    new Unique(),
    new Sorted(),
  }
);