首页 > 代码库 > 策略模式
策略模式
一、使用场景
一件事情可用多种方式完成
例子:出行旅游:我们可以有几个策略可以考虑:可以骑自行车,汽车,做火车,飞机。每个策略都可以得到相同的结果,但是它们使用了不同的资源。选择策略的依据是费用,时间,使用工具还有每种方式的方便程度 。
二、问题:如何让算法和对象分开,让策略与客户端隔离使用?
解决:策略模式——定义一系列的算法,把每个算法封装起来,并且可以是他们可以相互替换,本模式可以使算法独立于他的客户端变化。
三、具体实例:
以动物为例,随便举几个例子,鸡、鸭、鱼、猫、狗。
1)简单看一下动物的动作
- 鸡
public class Chicken {
public void drinkWater(){
System.out.println("喝水");
}
public void voice(){
System.out.println("咯咯!");
}
public void walk(){
System.out.println("两条腿走路");
}
public void fly(){
System.out.println("挥动翅膀飞");
}
}
- 鸭
public class Duck {
public void drinkWater(){
System.out.println("喝水");
}
public void voice(){
System.out.println("嘎嘎!");
}
public void walk(){
System.out.println("两条腿走路");
}
public void fly(){
System.out.println("挥动翅膀飞");
}
}
- 鱼
public class Fish {
public void drinkWater(){
System.out.println("喝水");
}
public void swim(){
System.out.println("游泳!");
}
}
- 猫
public class Cat {
public void drinkWater(){
System.out.println("喝水");
}
public void voice(){
System.out.println("喵喵!");
}
public void walk(){
System.out.println("四条腿走路");
}
}
- 狗
public class Dog { public void drinkWater(){ System.out.println("喝水"); } public void voice(){ System.out.println("汪汪!"); } public void walk(){ System.out.println("四条腿走路"); } }
2)好多重复动作,重复代码,为什么不抽取一个父类呢?
两种抽取思路:
①抽取公共方法:
public class Animal { public void drinkWater() { System.out.println("喝水"); } }
注:这样抽取完后,继承父类就可以不用写drinkWater的方法了,但是鸡鸭都有两条腿走路和挥翅膀的方法,猫狗还都有四个腿走路的方法,还是有冗余方法...
②那就把所有方法放到父类
public class Animal { public void drinkWater() { System.out.println("喝水"); } public void chickenVoice(){ System.out.println("咯咯!"); } public void walk2(){ System.out.println("两条腿走路"); } public void fly(){ System.out.println("挥动翅膀飞"); } public void duckVoice(){ System.out.println("嘎嘎!"); } public void swim(){ System.out.println("游泳!"); } public void catVoice(){ System.out.println("喵喵!"); } public void walk4(){ System.out.println("四条腿走路"); } public void voice(){ System.out.println("汪汪!"); } }
注:子类不需要写任何方法了,但是你会发现,子类继承了父类所有方法后,任何一个动物都会飞会叫会好几条腿走路了...
3)所以,制定出了策略模式:
定义方法族,分别封装起来,让他们之间可以互相替换,此模式让算法独立于客户。
(以走路为例)
①定义方法族(接口),分别封装(写里边自己的方法,只是有关自己族的)
public Interface IWalk{
void walk();
}
②所有不同的走的类型单独定义一个单独的类,并实现这个接口,并重写这个方法
两条腿走路:
public class WalkBy2Legs implements IWalk{
@override
public void walk(){
System.out.println("两条腿走路")
}
}
四条腿走路:
public class WalkBy2Legs implements IWalk{
@override
public void walk(){
System.out.println("四条腿走路")
}
}
不会走路:
public class WalkBy2Legs implements IWalk{
@override
public void walk(){
System.out.println("不会走路")
}
}
③让算法变化独立于客户的使用
父类Animal
public class Animal{
protected IWalk iWalk;
public void drinkWater(){
System.out.println("喝水");
}
public void walk(){
iWalk.walk();
}
}
④每个动物自己的类,可以继承父类Animal ,实现原有的喝水,再在自己的构造方法中对iWalk赋值:iWalk = new WalkBy2Legs();就可以有不同的走路效果
接着写鸡和猫,其余的类似
鸡(当然两条腿走路的鸭子也是这样写)
public class Chicken extends Animal{
public Chicken(){
iWalk = new WalkBy2Legs();
}
public void drinkWater(){
System.out.println("喝水");
}
...
}
猫(当然四条腿走路的狗也是这样写)
public class Cat extends Animal{
public Cat(){
iWalk = new WalkBy4Legs();
}
public void drinkWater(){
System.out.println("喝水");
}
...
}
鱼
public class Fish extends Animal{
public Fish(){
iWalk = new WalkNoWay();
}
public void drinkWater(){
System.out.println("喝水");
}
...
}
注:模式的组成:
接口IWalk,方法walk()+实现类WalkBy2Legs,实现不同的walk()方法+父类中定义自己的接口,调用接口中的方法+最后每个自己的子类,继承父类,实现都有的方法,构造方法中接口赋值=new不同的类,实现不同的动作。
环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Strategy访问它的数据。
抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
总结:
这样看代码还是那么多,反而还多了,但是功能算法独立了,各自的算法想怎么写怎么写,一套算法写一遍就好。
1.算法没有在子类重复,一套算法。
2.变化之处独立出来,改变只变一处就好。
3.通过给每个接口设置入口,可以动态的改变行为方式。
策略模式