一、『策略模式』定义
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
什么是算法族?可以把每套行为想象成一个算法族,即某个行为接口及它的所有实现类称为一个算法族。
二、场景
直接看定义是一脸懵,下面通过具体场景来一步步说明。
场景:描述不同品种的鸭子,如枫叶鸭、力加鸭、橡皮鸭、诱饵鸭等。
2.1 步骤一
对于不同品种的鸭子,我们需要用不同的类来描述。这时我们可以用标准的面向对象方式,即设计一个鸭子的超类来统一描述所有品种鸭子的共同属性和行为,再让各种鸭子继承自超类。另外,不同品种鸭对于同种行为有不同的表现(比如叫声),我们可以在超类中把该行为方法抽象化,让各种鸭子类自己实现该行为方法。
2.2 步骤二
现在有个问题,如果超类有【叫声】和【飞行】两种行为,但对于子类诱饵鸭既不会飞也不会叫,橡皮鸭不会飞但会叫,我们可能会想到覆盖方法但不实现具体功能。既然这样,我们不就可以把【叫声】和【飞行】设计成接口吗,当鸭子需要【叫声】和【飞行】就去实现这两个接口,而不需要这两个行为就不去实现接口。
设计原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
2.3 步骤三
现在又有个问题,因为是实现接口,而多种鸭子的【叫声】或者【飞行】可能相同,那么相应的实现也就相同了,我们会发现这部分的代码重复太多,并没有复用。这时我们可以针对接口编程,而不是针对实现编程。即对于【叫声】和【飞行】这两个接口,我们不是去实现它们,而是通过接口多态来使用。
设计原则:针对接口编程,而不是针对实现编程。
具体方法就是,对于【叫声】和【飞行】这两个接口我们是单独创建类来实现它们,而不是鸭子子类去实现。比如【吱吱叫】类或者【呱呱叫】类就是实现【叫声】接口,然后在鸭子超类中定义一个实例变量,即【叫声】这个接口变量,然后在子类中用多态 【叫声】 超类的接口变量 = new 【呱呱叫】 来使用。详细看Java代码:
// 飞行接口
interface FlyBehavior{
void fly();
}
// 叫声接口
interface QuackBehavior{
void quack();
}
// 实现飞行接口(会飞)
class FlyWithWings implements FlyBehavior{
public void fly(){
//鸭子飞行
}
}
// 实现飞行接口(不会飞)
class FlyNoWay implements FlyBehavior{
public void fly(){
//鸭子不会飞行,什么也不做
}
}
// 实现叫声接口(呱呱叫)
class Quack implements QuackBehavior{
public void quack(){
//鸭子呱呱叫
}
}
// 实现叫声接口(吱吱叫)
class Squeak implements QuackBehavior{
public void quack(){
//鸭子吱吱叫
}
}
// 实现叫声接口(不会叫)
class MuteQuack implements QuackBehavior{
public void quack(){
//鸭子不会叫,什么也不做
}
}
/***************************我是分界线***************************/
// 鸭子超类
abstract class Duck{
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
}
//橡皮鸭(不会飞但会吱吱叫)
class RubberDuck extends Duck{
public RubberDuck(){
flyBehavior = new FlyNoWay();
quackBehavior = new Squeak();
}
}
//诱饵鸭(既不会飞也不会叫)
class DecoyDuck extends Duck{
public DecoyDuck(){
flyBehavior = new FlyNoWay();
quackBehavior=new MuteQuack();
}
}
参考
《HeadFirst设计模式》