首页 > 代码库 > 策略模式

策略模式

一、使用场景

一件事情可用多种方式完成

例子:出行旅游:我们可以有几个策略可以考虑:可以骑自行车,汽车,做火车,飞机。每个策略都可以得到相同的结果,但是它们使用了不同的资源。选择策略的依据是费用,时间,使用工具还有每种方式的方便程度 。

技术分享

二、问题:如何让算法和对象分开,让策略与客户端隔离使用?

解决:策略模式——定义一系列的算法,把每个算法封装起来,并且可以是他们可以相互替换,本模式可以使算法独立于他的客户端变化。

三、具体实例:

以动物为例,随便举几个例子,鸡、鸭、鱼、猫、狗。
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.通过给每个接口设置入口,可以动态的改变行为方式。

 

策略模式