例子
需求:实现多种鸭子,鸭子有swim()、quack()、display()等方法。
第一种实现:设计一个鸭子的超类,然后不同种类的鸭子都继承此超类。这样使得部分方法得到复用,部分方法被重写。比如某种鸭子的外观是白色,某种鸭子的外观是黄色,那就重写父类的display()方法。
这似乎是个很正常的实现方式。但是,这时候有了新的需求。鸭子除了以上方法,还要添加fly()方法。如果按照第一种实现,那超类就必须添加fly()。这样问题就来了,并不是所有鸭子都具有飞行能力的,比如橡皮鸭、木头鸭,但是它还是继承了父类的fly()方法,那么我们必须在子类中重写该方法。
因此这种实现,会有以下缺点:代码在多个子类中重复;运行时的行为不容易改变;很难知道所有鸭子的全部行为;改变会牵一发动全身;
第二种实现:将某些易变的方法抽取出来,作为接口。那么父类包括swim()、display()方法,子类继承父类,再选择实现Flyable和Quackable接口。子类重写父类中的方法并实现接口中的fly()和quack()方法。
这样如果不会飞、不会叫的鸭子子类就不用实现Flyable和Quackable接口。似乎是解决了部分问题(不会再有具有fly()的橡皮鸭),但是却造成代码无法服用(如果多种鸭子的飞行方式、叫声是一样的)。
第三种实现:设计Flyable和Quackable接口,每种不同的飞行方式、叫声都是Flyable和Quackable接口的实现。在鸭子的超类中,声明Flyable和Quackable类型的行为变量,再添加performQuack()和performFly()方法,分别执行行为变量的方法,即quackBehavior.quack(), flyBehavior.fly()。而子类只要继承父类,然后声明不同的行为接口的实现的对象,赋值给接口类型的行为变量。
这样,行为类独立于鸭子类,同时行为类的代码可以得到复用,运行时可改变行为(修改行为变量即可),不需要重写父类的行为方法。同时,如果新增行为,不会影响到既有的行为类,也不会影响使用到飞行行为的鸭子类。这样就有了继承的“复用”好处,却没有继承所带来的包袱。
总结
设计模式:策略模式
策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
原则
- 封装变化
- 多用组合,少用继承
- 针对接口编程,不针对实现编程
设计模式的好处
- 设计模式是针对设计问题的通用解决方案,可以让我们建造出良好OO设计质量的系统
- 设计模式让开发人员之间有共享的语言,而不用去计较细节