【问题标题】:decorator design pattern violating is-a relationship违反 is-a 关系的装饰器设计模式
【发布时间】:2014-06-12 17:45:12
【问题描述】:

我最近开始研究装饰器设计模式,但我有一个疑问。装饰器实现了与它们试图装饰的组件相同的接口。这不违反 is-a 关系。 而且既然装饰器有组件(通过组合),为什么装饰器真的需要实现与具体组件相同的组件接口呢?

浏览Headfirst上的装饰器设计模式,感觉装饰器可以直接实现组件。装饰器不需要抽象类/接口。

我担心这可能真的是一个愚蠢的问题,但帮助会让我有一个坚实的基础。

【问题讨论】:

  • 投反对票的能解释一下吗?
  • 属于programmers.stackexchange.com
  • 完全实用。作为一名软件工程师,我每天都必须应用像装饰器这样的模式。我喜欢了解为什么它比替代品更有价值。
  • @Alex:你到底在说什么?当然可以解释模式。并且可以回答有关它们的问题。这些问题可能涉及理论,而模式体现了设计原则。
  • @Alex:单例是一种设计模式,其中程序强制只创建一个类的一个实例。 你是说我不只是解释单例,或者说单例不是设计模式?

标签: java decorator


【解决方案1】:

您可以根据用例选择如何实现装饰器类。 Decorator 类不需要实现相同的接口。

所以如果你看到 Collections.synchronizedCollection.(Collection<T> c) ,我们这里有一个静态方法,它充当装饰器,并且没有实现相同的接口。

但在 implementationshown 中,这个 link Decorator 类确实实现了用例需要的接口[因为使用了多态性]。

所以它不是强制性的,也没有破坏“是”关系。

【讨论】:

    【解决方案2】:

    了解组合和装饰器之间的区别很重要。装饰器是一种组合形式,但使其与众不同的主要之处在于,它这样做的方式是让通常使用装饰对象的代码可以使用包装器。

    让我们用一个常见的例子来帮助探索这个问题。考虑接口InputStream。我可能有一种将字节从一个流复制到另一个流的方法:

    public static void copy(InputStream in, OutputStream out) { ... }
    

    现在假设我们有一个要复制的文件。我会创建一个FileInputStream 并将其传递给copy()

    但是假设我有一个要求,我需要计算被复制的字节数。

    好吧,我可以创建扩展 FileInputStreamCountingFileInputStreamCountingFileInputStream 是一个FileInputStream。但是如果明天我需要为SocketInputStream 做同样的事情呢?我必须创建一个扩展 SocketInputStreamCountingSocketInputStream

    我可以改用合成!我可以创建一个接受 InputStream 并计算读取到它的字节数的类:

    public class StreamCounter {
    
       private final InputStream in;
       private long bytesRead;
    
       public int read() {
         int nextByte = in.read();
         if (nextByte != -1) bytesRead++;
         return nextByte;
       }
    }
    

    这可以处理任何 InputStream,这很棒。但是我们不能使用我们现有的带有InputStream 的代码,因为StreamCounter is-not-an InputStream

    这就是装饰器的用武之地。我们可以创建一个CountingInputStream,它既实现了InputStream(所以is-an InputStream)并委托给另一个InputStream。这样我们就可以在 copy() 方法中使用它。

    简而言之,就is-a 关系而言,CountingInputStreamInputStream(这通常是我们所关心的)但它不是FileInputStream,它允许它换行任何InputStream,比如一个LimitInputStream,它正在装饰一个DeflaterInputStream,它正在装饰一个BufferedInputStream,它正在装饰一个FileInputStream。归根结底,copy() 不需要关心!

    【讨论】:

    • BufferedInputStream 和 LineNumberInput Stream 正在扩展 FilterInputStream。因此,FilterInputStream 充当抽象装饰器类。现在 FilterInputStream 扩展了 InputStream(装饰器模式的组件)。这个FilterInputStream需要什么。即使 BufferedInputStream 直接扩展 BufferedInputStream,也能达到同样的目的吧?因此,总而言之,我无法理解抽象装饰器类的意义。与上面来自 java.io 的示例不同,很多时候抽象装饰器并没有与组件建立 is-a 关系。
    • 由于空间不足,无法感谢您花时间让我在最后的评论中理解这一点。感谢您的帮助
    • @TarunBhatt: FilterInputStream 只是一个方便的类,可以更轻松地实现InputStreams 的装饰器。实现该模式不是必需的。它基本上只是将其所有方法委托给一个包装好的InputStream。这很有用,因为许多装饰器不需要更改 every 方法的行为。例如,CountingInputStream 不需要更改 flush()close(),所以 FilterInputStream 已经这样做很方便。
    • 好吧,我想我现在变得更清晰了。这意味着像 FilterInputStream 这样的装饰器类将由需要装饰的方法组成,而不是 InputStream(组件)中的所有方法。
    猜你喜欢
    • 2013-11-28
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多