本教程总结自 "Head Frist Design Pattern",有兴趣的朋友可以去看下,是本不错的书。
我们先从一个例子看起,例如我们要创建一个Duck类,Duck类里面有quack(), swim(), display() 方法,然后我们可以创建DuckA, DuckB, DuckC...去继承Duck类。
你创建的类图可能是如下的:
其中display() 是一个抽象方法,DuckA, DuckB, DuckC分别实现自己的方法。现在假设我们要加上一个创建能飞的鸭子,你可能回想在Duck类中加上fly()方法,这时你的类图如下:
但是这样会造成一个问题,那就是鸭子到处飞,你可能会想到在子类中覆盖掉fly()方法,对已不会飞的鸭子在fly()方法中什么都不做。现在设想一下,如果有一百个Duck子类,其中有90个不会飞,你么你得在这90个子类中都覆盖一次fly()方法,代码的重复利用率为零。
这时你可能想到了接口,于是你的类图可能是如下:
代码利用率好像有了提高,请但仔细看一下,接口是不具有实现的,也就是说你还是得在继承接口的每个类中重写方法,这个类图和上面那个类图在本质上是一样的。
我们首先来分析下问题:每个Duck都会swim(),这个方法是不变的,每个Duck都有一个display()方法,而且都不相同,一部分Duck用方式A fly(),一部分用方式B fly()...一部分Duck用方式A quack(),一部分用方式B quack()。从上面的分析中我们发现swim()方法是通用的可以放在Duck类中,display()方法每个Duck类都要实现,因此作为abstract方法放在Duck中,而fly()和quack()方法则是不同组的鸭子有不同的行为,也就是DuckA具有A类型的fly(),DuckB具有B类型的fly()。要想让会飞的鸭子才能飞,会叫的鸭子才能叫,而且又要提高代码的重复利用率,我们可以利用组合,也就是每个鸭子都有一种fly()行为,一种quack()行为。因此我们在Duck类中添加两个变量flyBehavior,quackBehavior,然后实现set方法。我们抽象出Flyable和Quackable接口,然后分别用不同的子类去实现上面的两个接口。类图如下:
这时我们可以发现我们可以很容易的改变Duck的fly()行为和quack()行为,而且代码的利用率很高,这就是策略模式。有以下三点:
1.找出应用中需要变化的代码,将她们独立出来;
2.针对接口编程(interface或者abstract class),不要针对实现编程;
3.多用组合,少用继承。