设计模式,对大家来说都不陌生,但是里面的东西和武功一样,悟 了就简单,不然你永远可以知道,但是使用的都是皮毛,下面我借Head First 书里面的,给想我一样的新手,开拓一下思维,了解为什么要使用设计模式:
假设,现在要做一套模拟鸭子的游戏,我该如何设计?
我们先设计一个鸭子的超类(Superclass),然后让各种鸭子都集成这个类,当然,里面定义了一些公共方法,鸭子都有的。
public class Duck { public void quack() {// 呱呱叫} public void swin(){// 游泳} // 其他方法.. }
另外两个类:MallerDuck 和 RedheadDuck ,实现自己的外观
public class MallarDuck extends Duck{ public void display(){ // 绿毛鸭 } }
public class RedheadDuck extends Duck{ public void display(){ // 红毛鸭 } }
OK,那么现在公司要求,鸭子会飞。可能你说简单嘛,给父类加上 fly() 方法
public class Duck { public void quack() { // 呱呱叫 } public void swin(){ // 游泳 } public void fly(){ // 飞 } }
但是当进行测试的时候,发现很多玩具鸭子,也在飞...,老板很尴尬。当初客户也没说有玩具鸭子啊?但是开发的明白一点,需求是可变的,它永远是追寻更大的利益化,只要能让使用的人满意,没办法。
仔细一样,可以进行方法覆盖,那么玩具鸭子有自己的行为,总飞不起来了嘛
public class DecoyDuck extends Duck{ public void quack() { // 玩具鸭子,唧唧叫 } public void swin(){ // 游泳 } public void fly(){ // 什么都不做,不能飞 } public void display(){ // 这是玩具鸭 } }
现在又接到消息说,为了创新,可能会出现各种不同的鸭子,但是很多fly()等方法会一样,那么不是要重复的去写很多fly()和quart()的方法吗,会写很多,痛苦!这时候我想到接口,为特殊的行为制定接口,需要才去实现。
public interface Quackable { public void quack(); } public interface Flyable { public void fly(); } // 等等
然后其他去实现接口
public class MallarDuck implements Flyable,Quackable{ public void display(){ // 绿毛鸭 } @Override public void fly() { } @Override public void quack() { } } // 其他的类似
但是 这样还是觉得并没有实质的进展,如果 有N多的鸭子,那么得重复多少代码啊!
这让我们引出的一个真理:软件开发中,唯一不变得是变化。
我想起了经常说的一句话:设计是因为未来而存在
此时的代码无论是重用性和复杂度 以及修改 都不好,我们引出一个很重要的设计原则:
找出程序中可能需要变化的部分,把他们独立出来,进行封装,不要和那些不需要变化的代码放一起。结果就是可以轻易的改动或者扩展 要变化的部分,而不引起其他不需要变化的部分。
为了达到代码重用,又方便扩展的情况,我先把Duck 不变得 swim() 独立出来,然后把fly() 和 quack ()这些会变得行为拿出来,看看代码怎么做:
public class Duck { public void swin(){ // 游泳,共有的部分 } } public interface FlyBehaviour { // 飞 这个行为的接口,下面同理 public void fly(); } public interface QuackBehaviour { // 叫的接口 public void quack(); } public class FlyWithWing implements FlyBehaviour{ @Override public void fly() { // 会飞的 鸭子 // 具体实现,可以共用的代码,下面同理 } } public class FlyNoWay implements FlyBehaviour{ @Override public void fly() { // 不会飞 的鸭子 } } // 下面 quck 同理 public class QuackOne implements QuackBehaviour{ @Override public void quack() { // 普通鸭子 呱呱叫 } } public class QuackTwo implements QuackBehaviour { @Override public void quack() { // 橡皮鸭子 唧唧叫 } }
OK,现在的代码,灵活性就更高了。比如我现在可能会添加更多的鸭子,那么无论是会飞的,不会飞的,这些代码是可以重用的,如果需要添加 另外的叫声,我们同样可以创建一个新的QuackThree 去实现接口,也是可以扩展的,现在的代码是不是好很多了呢?
说了这么多,我们初略分析一下, 拿到需求的时候,不要简单的直接开始写代码,为了程序的灵活性,我们应当做一些考虑,这样为我们以后减少工作量做准备。因为程序时间长的部分是维护,开始时间最短,那么我们应该这样去思考,形成习惯,慢慢代码就会好很多了。