Duck 实例策略模式 - Head first 设计模式

Duck example strategy pattern - Head first design pattern

我想问一下这本书上duck的例子,让我很困惑,觉得很矛盾。

  1. 问题

  2. 结论

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

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

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

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

函数 performFly() 将调用 fly() 函数来选择 class。

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

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

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

它在示例中的作用是在parent class 中定义"behaviors"。在 parent class 中,您定义 Duck 可以具有飞行行为和嘎嘎行为。但这并不意味着 children classes 必须嘎嘎或飞。

你可以有一只不会飞的鸭子,当你调用 "fly" 它什么都不做,因为我们会有 "non-flying" 行为。

无需在 class 中对鸭子的行为进行硬编码,您可以随时更改这只鸭子的行为。

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

no client should be forced to depend on methods it does not use

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

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

仔细一看,"FlyNoWay"只是一个伪class,为了解决多态问题而引入的一种不恰当的方式

正确的方法是使用接口。

class Duck
{
    swim();
}

class MallardDuck : IFlyable
{
    fly();
}

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

代码重用呢?那你得把接口做的越严格越好,保证接口的大部分改动都会导致程序编译不通过