策略模式:对于父类中变化行为的部分,分别对其封装行为接口,实现行为族(算法族),
在子类里具体设定行为对象(也就是new 一个对象,注意到的是父类只是声明对象).
原则是:分离变换部分,封装接口,基于接口编程各种功能.此模式让行为算法的变换独立
于算法的使用者!
使用策略模式需要注意到的几点:
1.分析项目中变化部分与不变化的部分
2.多用组合少用继承;用行为类组合(也就是行为族),而不是行为的继承,这样更具有弹性
3.设计模式是没有响应的库直接提供你使用的!注意到的是:有些库或者框架本身就用某种设计模式设计的
**GreenHead**
--GoodFly--
__GaGa__
~~im swim~~
**RedHead**
--BadFly--
__GeGe__
~~im swim~~
**RedHead**
--NoFly--
__NoQuack__
需要注意到的是:这里的BadFly GeGe NoFly NoQuack我没有一一写出来,道理和GoodFly等等一样
最后总结一下:
这个模拟鸭子的项目:通过策略模式把变化的部分封装成行为的接口族(族:代表有很多接口),然后单独开对应行为接口族的实现类,那么调用的时候只需要调用接口族的类名即可,这样就不必要在子类中写重复的代码了,提高了代码的复用性和扩展性!
在子类里具体设定行为对象(也就是new 一个对象,注意到的是父类只是声明对象).
原则是:分离变换部分,封装接口,基于接口编程各种功能.此模式让行为算法的变换独立
于算法的使用者!
使用策略模式需要注意到的几点:
1.分析项目中变化部分与不变化的部分
2.多用组合少用继承;用行为类组合(也就是行为族),而不是行为的继承,这样更具有弹性
3.设计模式是没有响应的库直接提供你使用的!注意到的是:有些库或者框架本身就用某种设计模式设计的
下面我们就以一个模拟鸭子的游戏来说明策略模式:(重要代码都给了注释):
父类(超类):
Duck.java:
package com.java.hexter.stimulateduck.duck;
import com.java.hexter.stimulateduck.flybehavior.FlyBehavior;
import com.java.hexter.stimulateduck.quackbehavior.QuackBehavior;
///超类 也就是父类
public abstract class Duck {
///通过策略模式:超类里面放的是行为的对象(这里是mFlyBehavior和mQuackBehavior)
FlyBehavior mFlyBehavior;
QuackBehavior mQuackBehavior;
public Duck() {///构造函数
}
public void Fly() {///在超类中不会写集具体的代码实现
mFlyBehavior.fly();
}
public void Quack() {
mQuackBehavior.quack();
}
public abstract void display();
///通过set方法可以改变对象的属性,动态的变化,而不是只是简单的通过构造函数初始化一下(一成不变)
public void SetQuackBehavoir(QuackBehavior qb) {
mQuackBehavior = qb;
}
public void SetFlyBehavoir(FlyBehavior fb) {
mFlyBehavior = fb;
}
public void swim() {///共同的行为就可以放到超类中
System.out.println("~~im swim~~");
}
}
接下来就是Duck的两个子类:GreenHeadDuck.java和RedHeadDuck.java
GreenHeadDuck.java:
package com.java.hexter.stimulateduck.duck;
import com.java.hexter.stimulateduck.flybehavior.GoodFlyBehavior;
import com.java.hexter.stimulateduck.quackbehavior.GaGaQuackBehavior;
public class GreenHeadDuck extends Duck {
///超类中访接口对象 子类中具体设定行为对象(也就是new一个对象)
public GreenHeadDuck() {
mFlyBehavior = new GoodFlyBehavior();
mQuackBehavior = new GaGaQuackBehavior();
}
///我们这里只对行为和飞行做处理, display就不处理了
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("**GreenHead**");
}
}
RedHeadDuck.java:
package com.java.hexter.stimulateduck.duck;
import com.java.hexter.stimulateduck.flybehavior.BadFlyBehavior;
import com.java.hexter.stimulateduck.quackbehavior.GeGeQuackBehavior;
public class RedHeadDuck extends Duck {
public RedHeadDuck() {
mFlyBehavior = new BadFlyBehavior();
mQuackBehavior = new GeGeQuackBehavior();
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("**RedHead**");
}
}
然后就是封装行为的接口(FlyBehavior.java和QuackBehavior.java)
FlyBehavior.java:
package com.java.hexter.stimulateduck.flybehavior;
public interface FlyBehavior {
///注意到的是:我们把方法封装成了一个行为接口,多个行为接口就形成了一个行为族(算法族)
///一般的思路都是:子类继续父类,没有实现的方法在子类中实现,这里是把子类中实现的代码
///提取出来 形成一个行为接口 然后再单独安排对应的实现类去实现,这样的好处就是不要重复
///的写相同的代码,只需要调用行为接口的对象即可,这就是策略模式的精华(需要注意到的是:
///策略模式只针对行为中变化的部分,一成不变,换句话说就是父类的某一特点子类都有且一样,不变的
///部分直接写在父类里面就Ok了)
void fly();
}
QuackBehavior.java:
package com.java.hexter.stimulateduck.quackbehavior;
public interface QuackBehavior {
void quack();
};
然后就是这些行为接口的实现类(这里只各举一种):
GoodFlyBehavoior.java:
package com.java.hexter.stimulateduck.flybehavior;
public class GoodFlyBehavior implements FlyBehavior
{
@Override
public void fly() {
// TODO Auto-generated method stub
System.out.println("--GoodFly--");
}
}
GaGaQuackBehavoir.java:
package com.java.hexter.stimulateduck.quackbehavior;
public class GaGaQuackBehavior implements QuackBehavior
{
@Override
public void quack() {
// TODO Auto-generated method stub
System.out.println("__GaGa__");
}
}
接下来就是主函数的调用了:
创建一个名为StimulateDuck.java:
package com.java.hexter.stimulateduck;
import com.java.hexter.stimulateduck.duck.Duck;
import com.java.hexter.stimulateduck.duck.GreenHeadDuck;
import com.java.hexter.stimulateduck.duck.RedHeadDuck;
import com.java.hexter.stimulateduck.flybehavior.NoFlyBehavior;
import com.java.hexter.stimulateduck.quackbehavior.NoQuackBehavior;
public class StimulateDuck {
public static void main(String[] args) {
///这里之所以用了Duck 而不用对应自己的类名 原因:多态性,易于程序的扩展
Duck mGreenHeadDuck = new GreenHeadDuck();
Duck mRedHeadDuck = new RedHeadDuck();
mGreenHeadDuck.display();
mGreenHeadDuck.Fly();
mGreenHeadDuck.Quack();
mGreenHeadDuck.swim();
mRedHeadDuck.display();
mRedHeadDuck.Fly();
mRedHeadDuck.Quack();
mRedHeadDuck.swim();
mRedHeadDuck.display();
mRedHeadDuck.SetFlyBehavoir(new NoFlyBehavior());
mRedHeadDuck.Fly();
mRedHeadDuck.SetQuackBehavoir(new NoQuackBehavior());
mRedHeadDuck.Quack();
}
}
输出的结果为:**GreenHead**
--GoodFly--
__GaGa__
~~im swim~~
**RedHead**
--BadFly--
__GeGe__
~~im swim~~
**RedHead**
--NoFly--
__NoQuack__
需要注意到的是:这里的BadFly GeGe NoFly NoQuack我没有一一写出来,道理和GoodFly等等一样
最后总结一下:
这个模拟鸭子的项目:通过策略模式把变化的部分封装成行为的接口族(族:代表有很多接口),然后单独开对应行为接口族的实现类,那么调用的时候只需要调用接口族的类名即可,这样就不必要在子类中写重复的代码了,提高了代码的复用性和扩展性!