阅读以下关于设计模式应用的叙述,根据要求回答问题。
[说明]
某软件公司承接了一项面向儿童的模拟游戏软件的开发任务,该游戏软件主要模拟现实世界中各种鸭子的发声特征、飞行特征和外观特征。游戏软件需要模拟的鸭子种类及其特征如表2—13所示
表2—13鸭子种类及其特征 | |||
鸭子种类 | 发声特征 | 飞行特征 | 外观特征 |
灰鸭(MallardDuck) | 发出“嘎嘎”声(Quack) | 用翅膀飞行(FlyWithWings) | 灰色羽毛 |
红头鸭(RedHeadDuck) | 发出“嘎嘎”声(Quack) | 用翅膀飞行(FlyWithWings) | 灰色羽毛、头部红色 |
棉花鸭(CottonDuck) | 不发声(QuackNoWay) | 不能飞行(FlyNoWay) | 白色 |
橡皮鸭(RubberDuck) | 发出橡皮与空气摩擦的声音(Squeak) | 不能飞行(FlyNoWay) | 黑白橡皮颜色 |
[问题2]
请用400字以内的文字指出该公司架构师所采用的设计模式的适用性,以及图2-9中需要考虑哪些实现问题
参考答案:在以下情况中,应该使用Strategy模式。
(1)许多相关类只是在行为方面有所区别。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
(2)需要使用一个算法的不同变体。例如,定义了一些反映不同的空间或时间权衡的算法,当这些变体实现为一个算法的类层次时,可以使用策略模式。
(3)算法使用客户端未知的数据,可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
(4)一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。
依题意,在图2-9中,需要考虑以下一些Strategy模式实现问题。
(1)定义类Duck和类FlyBehavior(或类QuackBehavior)接口。这些接口必须使得类FlyWithwings、类FlyNoWay、类Quack、类Squeak和类QuackNoWay等能够有效地访问它所需要的类Duck中的任何数据,反之亦然。一种解决办法是让类Duck将数据放在参数中传递给类FlyBehavior(或类QuackBehavior)操作,也就是说,将数据发送给类FlyBehavior(或类QuackBehavior)。这使得类FlyBehavior(或类QuackBehavior)和类Duck解耦。但从另一个角度考虑,类Duck也可能发送一些类FlyBehavior(或类QuackBehavior)不需要的数据。
另一种解决办法是让类Duck将自身作为一个参数传递给类FlyBehavior(或类QuackBehavior),该类FlyBehavior(或类QuackBehavior)再显式地向类Duck请求数据;或者类FlyBehavior(或类QuackBehavior)可以存储对它的类Duck的一个引用,这样根本不再需要传递任何东西。这两种情况下,类FlyBehavior(或类QuackBehavior)都可以请求到它所需要的数据。但要求类Duck必须对它的数据定义一个更为精细的接口,这将使得类FlyBehavior(或类QuackBehavior)和类Duck更加紧密地耦合在一起。
(2)将类FlyBehavior(或类QuackBehavior)作为模板参数。例如,在C++中,可利用模板机制用一个Strategy来配置一个类。然而这种技术仅当下面条件满足时才可以使用:可以在编译时选择Strategy;它无须在运行时改变。在这种情况下,要被配置的类(如类Duck)被定义为以一个Strategy类作为一个参数的模板类。使用模板不再需要定义给类FlyBehavior(或类QuackBehavior)定义接口的抽象类。把类FlyBehavior(或类QuackBehavior)作为一个模板参数也使得可以将一个类FlyBehavior(或类QuackBehavior)和它的类Duck静态地绑定在一起,从而提高效率。
(3)尽量使类FlyBehavior(或类QuackBehavior)成为可选的对象。即使在不使用额外的FlyBehavior(或类OuackBehayior)对象的情况下,类Duck也还有意义,那么它还可以被简化。类Duck在访问类FlyBehavior(或类QuackBehavior)前先检查它是否存在,如果有,那么就使用它;如果没有,那么类Duck执行默认的行为。这种方法的好处是客户根本不需要处理FlyBehavior(或类QuackBehavior)对象,除非它们不喜欢默认的行为。