1.需求分析:
- 有一款《Duck》的游戏,游戏中存在很多的鸭子,主要会飞和叫。
- 鸭子有很多种,比如野鸭、家禽鸭、木头鸭和小黄鸭(一种放在浴室中的玩具)。
- 也许以后还会有更多的奇怪的鸭子,比如火箭鸭等等。
2.程序设计(此处主要关心fly()和quack()操作):
1.使用继承来实现对于更改操作的灵活程度:
在一个Duck基类中考虑一个鸭子应该具有的所有的通用的功能,实现鸭子们确定的共有的功能,非共有的部分,要求交给子类实现。
存在的问题:
- 所有的子类都被强加了通用的
fly()、quack()等操作了。 - 对于a,为了让
WoodenDuck等,不能fly()和quack(),只能在子类中重写方法,覆盖基类中的方法。 - 部分代码将在多个子类中重复。例如,
WoodenDuck和ToyDuck都不会飞,但要重写两次fly()。 - 难以在运行时改变鸭子们的行为。
-
2.抽象出部分功能成为接口以实现更加灵活的更改操作:
让“某些”而不是“全部”的鸭子可飞、可叫。在此,

存在的问题: 部分代码将在多个子类中重复。所以仍然难以复用。例如
WildDuck和HomeDuck都会quack()且相同,但是其代码将会重复两次。3.将抽象出的部分功能封装起来,尝试使得他们可以相互组合和替换。
⭐设计原则:找出应用中可能变化之处,把他们独立出来,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的其他部分。
对于本次需求,已知鸭子的
fly()和quack()会随着具体是什么鸭子的不同而不同。
所以应该将他们从基类Duck里剥离。基于面向对象原则,被剥离的部分将作为 类 或者 接口 以存在。⭐设计原则:面向接口(或抽象)编程,而不是针对具体实现编程。
fly()和quack()是操作,他们变成 类 或者 接口 后没有属性,因此,本次需求使用接口。
fly()就此变成接口Fly,它具体的实现是NormalFly、BriskFly和CanNotFly。
此时,鸭子的 飞 和 叫 已经独立于Duck,所以,Duck需要委托原来的两个操作给现在的Fly和Quack接口:首先,在
Duck类中添加两个 操作的实例变量,以便于后期指定操作接口的具体实现。- 在
Duck中写好调用 操作的实例变量 中方法的方法。 - 考虑是否设置
setFlyAction()等函数来使得鸭子能动态的改变 飞 等具体操作。

现在的Duck:
public abstract class Duck {protected Fly howToFly;protected Quack howToQuack;public abstract void display();public void flyPerform(){ //实现flyhowToFly.flyAction();}public void quackPerform(){ //实现quackhowToQuack.quackAction();}public void setFlyAction(Fly now){this.howToFly=now;}public void setQuackAction(Quack now){this.howToQuack=now;}}
抽象出来的、频繁变动的接口Fly:
public interface Fly {public void flyAction();}
具体的Fly实现、真正的 飞 操作的执行者、Duck最终委托的对象:
public class BriskFly implements Fly {@Overridepublic void flyAction() {System.out.println("BriskFly");}}
⭐设计原则:多用组合,少用继承。
在本次需求中鸭子的真正操作,由最终Duck中Fly howToFly=具体的Fly对象;决定,还可以使用Duck中提供的public void setFlyAction(Fly now);,来动态改变具体的Fly。而不再是使用继承来一个个重写。也许,写具体的Fly实现也会有些许麻烦,但是,我“有选择”一定比我“已经是”更好。
