从模拟鸭子应用做起
Joe准备做一套成功的模拟鸭子游戏。游戏中会出现各种鸭子,一边游泳戏水,一边呱
呱叫。
设计了一个鸭子超类(SuPerClass),并让各种鸭子继承此超类。
现在想让鸭子能飞
可怕问题发生了
Joe忽略了一件事,并非Duck所有的子类都会飞。
我们能做的,只有根据鸭子的特性,覆写fly()方法才可以,该fly()或者实现一定功能或者什么事都不做。
在超类中加上fly(),就会导致所有的子类都具备fly(),连那些不具备fly()的子类也无法免除。所以,当涉及“维护”时,为了“复用”(reuse)目的而使用继承,结果可能会很糟。
因为这样做(利用继承来提供Duck的行为),带来的不好的地方:
- 代码在多个子类中重复。
- 运行时的行为不容易改变。
- 不能直接看出该鸭子都有哪些行为(虽然有fly()方法,但里面什么事都没做)
- 改变会牵一发动全身,造成其他鸭子不想要的改变。
利用接口如何
把fly()从超类中取出来,放进一个“flyable接口”中,只有会飞的鸭子才实现此接口。同样的方式来设计“Quackable接口”,因为不是所有的鸭子都会叫。
想想这样如何?
……
虽然Flyable和Quackable可以解决“一部分”问题(不会再有会飞的橡皮鸭),但却造成代码无法复用,依然不够好。
变是永远不变的
不管你在何处工作,构建些什么,用何种编程语言,在软件开发上,一直伴随你的那个不变真
理是?
不管当初软件设计得多好,一段时间之后,总是需要成长与改变
否则软件就会“死亡”。
封装变化,从零开始
设计原则:找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
把变化的部分取出并封装起来,以便以后可以轻易地改动和扩充此部分,而不影响不需要变化的部分。
分开变化和不会变化的部分
你能想象出如何设计吗???