最近学习了OOD设计模式. 有一个模拟鸭子游戏的案例,出自<Head First 设计模式>,讲解了使用面向接口编程以及使用组合模式.
###场景重现
有如下图这样一个类设计图.
有一个名为鸭子的基类,然后可以创建很多类型的鸭子,如: 绿头鸭,红头鸭...
基类中,有quack()和swim()以及一个display()三个方法.
绿头鸭和红头鸭继承了鸭子类,那么自然拥有了quack()和swim()两个方法,但是还需要去实现一个display()的方法
很容易知道display()用来显示该鸭子的属性.

###问题 到这里,看起来一切都很好.但是需求增加了,需要添加一个飞的操作,如下图:


quack()方法重写了,因为橡皮鸭不能会飞,所以同样需要把fly()方法也重写一遍.
假设,如果我们还可以创建,烤鸭等等一系列不会飞的鸭子,那么我们都需要进行重写fly()方法.
如果我们在父类中又添加一个方法,可能同样会导致很多子类进行重写.
那么,这还是继承带给我们的好处吗?
将来加入一只木头的诱饵鸭,既不会飞,也不会叫,那么我们需要把quack()和fly()这两个方法也全部覆盖掉.
###解法
#####换个思路: 用接口怎样?
如下图:
我们添加两个接口,Flyable提供飞的方法,Quackable提供叫的方法.
让子类去实现各自需要的接口.

fly()方法和quack()方法的代码实现是一样.
这样一来代码就显得冗余了.
###面向对象的准则
- 发现变化并且封装变化
- 找出可变之处,把它独立出来,不要和那些不需要变化的代码混在一起.
- 一个抽象的过程.
- 针对接口编程而不是针对现实编程.
- 优先使用组合而不是继承.
###发现变化并且封装变化


如上图,我们可以创建中间类来继承接口,并且实现接口. 既然有不同种类的叫声,那么我们就创建三个中间类,分别去实现不同的叫声. ###针对接口编程

performQuack()方法中调用中间类的quack()方法.
将子类需要自己实现的方法作为抽象方法.
我们再看一下作为子类需要怎么写.

###总结 这个例子很清晰易懂,弄明白了组合模式的解耦,以及代码的封装和单一原则等. 设计模式还是要好好学的,可能项目中不会太多的用到,但是对于写框架有很大的帮助.
本文大部分内容来源于 码农翻身 刘欣老师的讲课内容.可以微信搜索公众号"码农翻身"关注.