【问题标题】:Duck example strategy pattern - Head first design pattern鸭示例策略模式 - 头部优先设计模式
【发布时间】:2015-01-11 13:37:50
【问题描述】:

想请教一下这本书里鸭子的例子,这让我很困惑,感觉很矛盾。

  1. 问题

  2. 结论

他说“当 joe 向鸭子超类添加新行为时,他也在添加不适合 sume 鸭子类的行为

但在结论中他添加了performFly()performQuack(); 有什么不同,因为我认为它与he was also adding behavior that was not appropiate for sume Duck subclasses 相同?

**图片取自《Head first design pattern》一书 ** 这个问题并不是说这本书不好,我认为这本书真的很好。这只是我在问一些我没有从书中得到的东西。

【问题讨论】:

  • 他们所做的只是获取一个函数(quack)并将其分离到一个单独的类中。这有点复杂。最好创建一个名为“FlyingDucks”的鸭子类,然后将 Fly() 放在那里。然后,所有飞鸭子都将继承该类。或者,使 FLy() 抽象,强制每个子类定义飞行的含义。他们所做的工作更多,也更复杂。每个子类都需要选择一个 Fly 类来分配给 flyBehavior——即使它们不能飞行。
  • 如果我说the problemthe conclusion 是矛盾的,我说得对吗?或者我只是不明白他的意思?
  • 最好的设计是意识到,(虚构的)问题考虑鸭子的方式,橡皮鸭不是鸭子——它不会飞,也不会游泳(除非你包括浮动)等。如果出于某种原因,你真的想要一个包含真正的鸭子和橡皮鸭的类,那么你应该在这些项目中寻找共同点作为你的问题空间,并将它们作为共同属性;不要从你空间中某些项目共有的属性开始,然后将其他项目强制适应它。
  • 有一点需要注意,这是本书的第一章,还没有介绍他们可以用于这个解决方案的几个概念。很多时候他们说“这可能会做得更好,他们会在以后解决这个问题。” (释义)

标签: java php design-patterns


【解决方案1】:

我不是设计模式的专家,但是当我阅读那本书时,我对那个特定章节的第一感觉是接口的构建和实现方式违反了一个众所周知的编程原则: the Interface Segregation Principle (ISP) 基本上这个原则表明

不应强迫客户依赖它不使用的方法

因为一些不会飞的鸭子实现了 fly() 方法,即使它们不需要它。 也就是说,我认为在这种特殊情况下,实现所有接口方法是不可避免的,因为在客户端我们正在使用多态行为,我们需要确保即使未使用,我们也拥有所有可用的方法。

【讨论】:

    【解决方案2】:

    当您喜欢组合而不是继承时,策略模式会起作用http://en.wikipedia.org/wiki/Composition_over_inheritance

    这是一个很好的做法,因为您可以更改类的行为而无需更改任何代码。而且你也不需要一个巨大的类树。您还可以动态更改类的行为。

    它在示例中所做的是在父类中定义“行为”。在父类中,您定义 Duck 可以具有飞行行为和嘎嘎行为。但这并不意味着儿童班必须有嘎嘎或飞。

    你可以有一只不会飞的鸭子,当你调用“fly”时它什么也不做,因为我们会有一个“不会飞”的行为。

    您可以随时更改这只鸭子的行为,而不是硬编码鸭子在课堂上的行为。

    【讨论】:

      【解决方案3】:

      最后,他添加了两个具有fly() 函数的新类。但是,该功能并不总是能让鸭子飞起来。橡皮鸭不会飞,所以它们使用FlyNoWay 类的实例。其他可以飞行的鸭子使用FlyWithWings 类的实例。 Duck 类中的字段flyBehavior 可能会在构造函数中设置。

      函数performFly() 会为选择的任何类调用fly() 函数。

      正如 kainaw 在 cmets 中所说,这是一个相当复杂的解决方案。但是,它仍然可以使用。假设您正在创建一个鸭子设计程序。如果用户选择鸭子是否会飞,则不能硬编码。您可以创建一个布尔值,但您可能需要处理更复杂的情况,例如行为。您可能需要一个WildDuckBehavior 类和一个DomesticDuckBehavior,每个都有自己的关于如何操作的信息。基本上,书中的示例是如何使用它的简化版本。

      【讨论】:

      • 但是橡皮鸭还是继承了rubber duck不需要的“fly”?
      • @MuhammadRifkiMockie 我稍微误读了图表,所以我编辑了答案。这有帮助吗?
      【解决方案4】:

      你是对的。本书提供的解决方案存在一个大问题: “FlyNoWay”不是“FlyBehaviour”的子案例。 FlyBehaviour 要具有任何意义,必须具备飞行能力。从它继承的类将指定行为(使用翅膀等飞行)。子类包含的内容不能少于其继承自的类。

      细看,“FlyNoWay”只是一个伪类,是为了不恰当地解决多态问题而引入的。

      正确的方法是使用接口。

      class Duck
      {
          swim();
      }
      
      class MallardDuck : IFlyable
      {
          fly();
      }
      
      class RedheadDuck : IFlyable, IQuackable
      {
          fly();
          quack();
      }
      

      代码重用怎么样?那么你必须使接口尽可能严格,确保接口中的大多数更改都会导致程序无法编译。

      【讨论】:

        猜你喜欢
        • 2014-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-17
        • 2010-11-02
        • 1970-01-01
        相关资源
        最近更新 更多