【问题标题】:Confusion in Decorator Pattern装饰器模式的混乱
【发布时间】:2014-02-10 10:19:59
【问题描述】:

我正在阅读 Gof 的装饰器设计模式。我对以下几点感到困惑

  1. 它说模式的重要方面是它让装饰器 出现在使用组件的任何地方。客户不能 通常会区分装饰组件或 未装饰的组件?例如,如果我认为,我是客户,并且 基本组件与电子邮件有关,但我也希望它安全。 有人正在为我提供功能。

     Email email = new SecuredEmail(new TextEmail());
    

    问:这只是假设性的。作为客户我不知道吗 那个,这个短信是装饰的吗?我只是困惑,有人可以 澄清这个疑问?

  2. 装饰器及其组件不相同。装饰器充当 一个透明的外壳。但从对象身份的角度来看, 装饰组件与组件本身不同。 因此,当您使用装饰器时,您不应该依赖对象标识。 这是什么意思?

谁能解释一下这两部分。

【问题讨论】:

  • 你已经积累了创作和使用。这是两种完全不同的模式。在创作过程中,您必须了解一切。在使用过程中,您不需要这些知识。

标签: java design-patterns


【解决方案1】:

假设Email 是一个Java 接口。任何实现Email 的类都可以用来初始化变量email,包括任何装饰器,因为装饰器实现了一个接口或扩展了一个抽象类(实现了一个接口)。客户当然可以知道类实例是什么,但他们通常不需要这样做。只需使用email.getClass()

另一方面,装饰器与被装饰物不是同一个对象。它包裹了被装饰的对象。因此TextEmailSecuredEmail 不是同一个对象。如果代码看起来像:

TextEmail txtEmail = new TextEmail();
SecuredEmail securedEmail = new SecuredEmail(txtEmail);

然后检查他们的身份将给出下一个结果:

System.out.println("identical: " + (txtEmail == securedEmail));

identical: false

equals(Object) 可以写成这样可以给出不同的结果,例如

System.out.println("equal: " + txtEmail.equals(securedEmail));

输出:

equal: true

【讨论】:

  • 恕我直言,您违反了第二条声明。我看不出文本电子邮件应该等于安全电子邮件的原因。
  • 感谢@Vash - 在这种情况下没有理由让这两个对象相等。一般情况下可能是这样。
  • 感谢@Vash 和鲍里斯。所以简而言之意味着,基本上装饰器正在扩展一个抽象类,该类又实现或扩展组件接口,所以它们不能像身份一样是相同的?
  • 接受答案就可以了 ;-)
  • @BorisPavlović 会马上做,如果我的理解是正确的,你能确认我评论中的部分吗?
【解决方案2】:

你不是客户。使用电子邮件的代码是客户端,它只知道对象是电子邮件。它不会知道这是一个用 SecuredEmail 装饰的 TextEmail。

至于依赖对象标识,这意味着一段代码无论是通过 TextEmail 还是包裹在 SecuredEmail 中的 TextEmail 都应该以相同的方式工作。从技术上讲,你不应该依赖email1 == email2,因为 email2 可能是 email1 用 SecureEmail 装饰的。

【讨论】:

    【解决方案3】:

    Ad.1 作为客户,装饰类的用户,您无法确定您使用什么实现。

    我们需要假设Email,是一个接口,以免创建两个方法。

    方法一

     public Email getMail() {
       reutrn TextEmai();
     }
    

    方法二

     public Email getMail() {
       reutrn SecureEmail();
     }
    

    作为 API 的用户,您会知道存在一个具有方法 Email getMail() 的类,您无法通过它的描述来确定将解析哪个类。它可能是方法 1 或方法 2。但作为一个使用过的你不能确定。

    第二点,指对象相等。对于此示例,TextEmail 对象不等于 SecureEmail。正如鲍里斯在他的回答和 cmets 中解释的那样。装饰器可以但不必以相同的方式实现 equals 方法。因此,当使用装饰器模式时,您永远不应该信任或依赖相等性。

    【讨论】:

    • 所以简而言之,装饰器基本上是在扩展一个抽象类,该抽象类又实现或扩展组件接口,所以它们不能像身份一样是相同的?是的,正如鲍里斯解释的那样,如果我们以某种方式实现 equals,它可能会返回 true,但这完全取决于实现。我的理解正确吗?
    • 更多或更少是的。装饰器可以扩展任何非最终类或实现和接口,并将实例作为参数。但最后一点是用户(开发人员),你不能假设使用了什么装饰器或相信方法 equals 将以相同的方式用于装饰对象。
    猜你喜欢
    • 2015-07-25
    • 2019-02-27
    • 2020-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 1970-01-01
    相关资源
    最近更新 更多