【问题标题】:Decorator pattern implementations - extends vs implements装饰器模式实现 - 扩展与实现
【发布时间】:2018-12-23 20:52:17
【问题描述】:

我创建装饰器模式示例:

界面:

public interface Printer {
  void print(String message);
}

实现:

public class StringPrinter implements Printer {

  public void print(String message) {
    System.out.println(message);
  }
}

和 2 个装饰器:

将字符串改为大写:

public class UpCasePrinter implements Printer {

  private Printer printer;

  public UpCasePrinter(Printer printer) {
    this.printer = printer;
  }

  public void print(String message) {
    printer.print(message.toUpperCase());
  }
}

打印反向字符串:

public class InversePrinter implements Printer {

  private Printer printer;

  public InversePrinter(Printer printer) {
    this.printer = printer;
  }

  public void print(String message) {
    StringBuilder builder = new StringBuilder(message);
    printer.print(builder.reverse().toString());
  }
}

一切正常。但是在阅读不同站点上的示例时,我发现了不同的实现。每个描述符 extends 来自另一个。并且看到了BufferedInputStream的实现

BufferedInputStream extends FilterInputStream
FilterInputStream extends InputStream
public abstract class InputStream implements Closeable

我无法理解以下内容:

  1. 如何创建装饰器有区别吗?至于我 - 装饰器 implements 与原始类或示例中的接口相同 - 装饰器是来自另一个装饰器的 extends 等。link for extends realization

  2. 可能只是因为在开始时选择了抽象类而不是接口而在示例中使用了 BufferedInputStream 这样的实现?

编辑:

也就是说,我不明白CarDecorator有什么用

LuxerCarSportsCar可以implement Car接口和not extends来自CarDecorator。有什么好处?

【问题讨论】:

    标签: java design-patterns decorator


    【解决方案1】:

    BufferedInputStream 的实现方式与您的 Car 示例完全相同。它装饰了一个InputStream,尽管它是一个抽象类,但它仍然提供了一个契约,就像一个接口一样。在这种情况下选择了一个抽象类,因为有些方法具有默认行为(readskip),并且在编写该类时,接口无法支持这一点(现在可以,但 default methods in 接口是在很久以后添加的)。

    因为合约使用了一个抽象类,BufferedInputStream 扩展了FilterInputStream,就像CarDecorator 实现了Car。两者都只是代表的简单持有者。它们包含单个 protected 字段(InputStreamCar)并将所有方法调用委托给该字段。这样做的原因是,如果您的合约中有大量方法,则在每个装饰器中委派所有方法可能会导致大量代码重复。当你的接口只有一个方法时,就像你的那样,那么它提供的好处就很小。

    这当然不是装饰器模式的必要组成部分;这只是实现它的一种稍微不同的方式。您的实现仍然是 100% 正确的装饰器模式实现。

    【讨论】:

    • A BufferedInputStream 也是装饰器模式的一个例子,所以我不知道你为什么说它不是。
    • @MarkRotteveel 再次正确。我这么说是因为它没有使用通用接口,但你绝对可以证明这不是一个有意义的区别。我已经编辑澄清。
    • 嗯,它使用的是通用接口,只是它是在抽象类 (InputStream) 中定义的,而不是在文字接口中。但两者都被认为是理论上的接口。
    • @MarkRotteveel 当然,但装饰器模式的重点是支持组合而不是继承,所以我认为使用抽象类层次结构确实不遵循模式(这很好 -当然,并非所有事情都必须遵循一个模式)。按照该模式,BufferedInputStream 应该由FilterInputStream装饰,并且不应扩展它。
    • 我不完全同意你的看法。装饰就像缓冲区(文件输入)或流到阅读器(缓冲区(文件输入))等一样。继承用于共享流管道的通用实现,如果继承用于改变行为,那么你' d 得到类似BufferedFileInputStream(和BufferedSocketInputStream 等)的东西。当然,我猜如果现在设计它,它的设计可能会有所不同,但是为此使用继承的选择是合理的。
    猜你喜欢
    • 2012-02-16
    • 2011-03-08
    • 1970-01-01
    • 2019-03-25
    • 2013-07-02
    • 2021-04-07
    • 2020-02-29
    • 2018-03-10
    • 1970-01-01
    相关资源
    最近更新 更多