本人是Head First的书迷,最近刚入手设计模式一书,学习了策略者模式,与大家分享。
BOb的公司开发了一款模拟鸭子的游戏(SimDuck),游戏中的各种鸭子会戏水,呱呱叫。该系统内部设计使用了标准的OO技术,设计了一个鸭子超类。
?public class Duck{
? ?quack();
? swim();
}
随着公司业务的发展,现在需要把鸭子设计的可以飞起来。1.首先我们想到的解决方式就是在超类中加入fly()方法,其他的鸭子类继承超类就可以了。但是这就会导致一些问题,让本来就不会飞的鸭子也继承该类,就会有设计缺陷,就算是重写fly()方法,让该方法什么都不做,也会造成大量的代码冗余。2.利用接口如何?可以把fly()从超类中抽取出来,放进一个Flyable接口中,这样一来,只有会飞的鸭子才实现此接口,这虽然是一个不错一的方法,至少不会再有会飞的橡皮鸭(橡皮鸭不会飞),但是却造成代码无法复用,无论什么时候修改某个行为(比如修改接口中一个方法的返回值类型),必须得往下追踪并在每一个定义次行为的类中修改它,不小心,可能会造成新的错误。
这时候我们就需要一种设计模式来解决该问题,虽然会增加代码量(因为Java本来就是把小型项目开发成中型项目,把中型项目开发成大型项目,但是会易于我们后期的维护等一系列行为)。首先我们必须明白一个设计原则,就是把每次来需求会发生改变的代码抽取出来,和其他稳定的代码有所区分。
就我们这个例子来说,我们知道Duck类内的fly()和quack()会随着鸭子的不同而改变。为了要把这两个行为从Duck类中分开,将它们从Duck类中取出来,建立一组新类来代表每个行为。
设计鸭子的行为,我们希望一切能有弹性,我们可以动态的改变鸭子的行为。接着来看我们的第二个设计原则:针对接口编程,而不是针对实现编程。
我们利用接口代表每个行为,如FlyBehavior与QuackBehavior,而行为的每个实现都将实现其中的一个接口。所以这次鸭子类不会负责实现Flying与Quacking接口,反而是由我们制造一组其他类专门实现FlyBehavior与QuackBehavior,这就称为“行为”类。在我们新的设计中,鸭子的子类将使用接口(FlyBehavior)所表示的行为,所以实际的“实现”不会被绑死在鸭子的子类中(其实就是具体的编码写在了实现的FlyBehavior和QuackBehavior的类中)。
整合鸭子的行为。现在是鸭子会将飞行和呱呱叫的动作“委托”(delegate)别人处理,而不是定义在Duck类或子类的内的方法了。做法是这样的,首先在Duck类中“加入两个实例变量”,分别为“flyBehavior”与“quackBehavior”,声明为接口类型。
2.现在我们来实现performQuack();
public class Duck{
QuackBehavior quackBehavior;
public void performQuack(){
quackBehavior.quack();
}
}
想要进行呱呱叫的动作,Duck对象只要叫quackBehavior对象去呱呱叫就可以了。在这部分代码中,我们不在乎quackBehavior接口对象到底是什么,我们只关心该对象知道如何呱呱叫就够了。
3.我们现在来关心如何设定quackBehavior和flyBehavior的实例变量。
public class MallardDuck extends Duck{
public MallardDuck(){
//绿头鸭使用Quack类处理呱呱叫,所以当performQuack()被调用时,该职责被委托给Quack对象
quackBehavior=new Quack();
flyBehavior=new FlyWithWings();
}
}
关于在构造方法中注入对象,我们会在后续的模式中修正。总之我们要明白为什么要有这个设计模式,由于是第一次发,电脑上没有UML图的画图工具(用代码简单说明),后续一定补上。
BOb的公司开发了一款模拟鸭子的游戏(SimDuck),游戏中的各种鸭子会戏水,呱呱叫。该系统内部设计使用了标准的OO技术,设计了一个鸭子超类。
?public class Duck{
? ?quack();
? swim();
}
随着公司业务的发展,现在需要把鸭子设计的可以飞起来。1.首先我们想到的解决方式就是在超类中加入fly()方法,其他的鸭子类继承超类就可以了。但是这就会导致一些问题,让本来就不会飞的鸭子也继承该类,就会有设计缺陷,就算是重写fly()方法,让该方法什么都不做,也会造成大量的代码冗余。2.利用接口如何?可以把fly()从超类中抽取出来,放进一个Flyable接口中,这样一来,只有会飞的鸭子才实现此接口,这虽然是一个不错一的方法,至少不会再有会飞的橡皮鸭(橡皮鸭不会飞),但是却造成代码无法复用,无论什么时候修改某个行为(比如修改接口中一个方法的返回值类型),必须得往下追踪并在每一个定义次行为的类中修改它,不小心,可能会造成新的错误。
这时候我们就需要一种设计模式来解决该问题,虽然会增加代码量(因为Java本来就是把小型项目开发成中型项目,把中型项目开发成大型项目,但是会易于我们后期的维护等一系列行为)。首先我们必须明白一个设计原则,就是把每次来需求会发生改变的代码抽取出来,和其他稳定的代码有所区分。
就我们这个例子来说,我们知道Duck类内的fly()和quack()会随着鸭子的不同而改变。为了要把这两个行为从Duck类中分开,将它们从Duck类中取出来,建立一组新类来代表每个行为。
设计鸭子的行为,我们希望一切能有弹性,我们可以动态的改变鸭子的行为。接着来看我们的第二个设计原则:针对接口编程,而不是针对实现编程。
我们利用接口代表每个行为,如FlyBehavior与QuackBehavior,而行为的每个实现都将实现其中的一个接口。所以这次鸭子类不会负责实现Flying与Quacking接口,反而是由我们制造一组其他类专门实现FlyBehavior与QuackBehavior,这就称为“行为”类。在我们新的设计中,鸭子的子类将使用接口(FlyBehavior)所表示的行为,所以实际的“实现”不会被绑死在鸭子的子类中(其实就是具体的编码写在了实现的FlyBehavior和QuackBehavior的类中)。
整合鸭子的行为。现在是鸭子会将飞行和呱呱叫的动作“委托”(delegate)别人处理,而不是定义在Duck类或子类的内的方法了。做法是这样的,首先在Duck类中“加入两个实例变量”,分别为“flyBehavior”与“quackBehavior”,声明为接口类型。
2.现在我们来实现performQuack();
public class Duck{
QuackBehavior quackBehavior;
public void performQuack(){
quackBehavior.quack();
}
}
想要进行呱呱叫的动作,Duck对象只要叫quackBehavior对象去呱呱叫就可以了。在这部分代码中,我们不在乎quackBehavior接口对象到底是什么,我们只关心该对象知道如何呱呱叫就够了。
3.我们现在来关心如何设定quackBehavior和flyBehavior的实例变量。
public class MallardDuck extends Duck{
public MallardDuck(){
//绿头鸭使用Quack类处理呱呱叫,所以当performQuack()被调用时,该职责被委托给Quack对象
quackBehavior=new Quack();
flyBehavior=new FlyWithWings();
}
}
关于在构造方法中注入对象,我们会在后续的模式中修正。总之我们要明白为什么要有这个设计模式,由于是第一次发,电脑上没有UML图的画图工具(用代码简单说明),后续一定补上。