1.策略模式(Strategy Pattern)的适用场景
策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
2.策略模式的特点
(1)策略模式是一种定义一系列算法的方法,从概念上看,所有的这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
(2)策略模式简化的单元测试,因每个算法都有自己的类,可以通过自己的接口单独测试。
(3)该模式定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化,不会影响到适用算法的客户。
3.策略模式适用注意
(1)分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体设定行为对象。
原则就是:分离变化部分,封装接口,基于接口变编程实现各种功能。
(2)策略模式的注意点
a-分析项目中的变化部分与不变部分
b-多用组合少用继承,用行为类组合,而不是行为的继承,更有弹性
4.举例说明--模拟鸭子项目
(1)OO设计方式
需求分析:鸭子会叫、会游泳,但外观不一样
(2)新需求:要求鸭子会飞(可扩展性)
问题来了:超类的修改使得所有的鸭子都会飞,与实际不符(如:煮熟的鸭子不会飞)
继承带来的问题:对超类的局部改动,会影响其他部分,影响会有溢出效应
OO解决方式:子类中复写fly()方法-->工作量大,代码重复量大,不是一种好的设计方式
(3)策略模式-应对项目的扩展性,降低复杂度
**提取项目的变化部分,抽象成接口+实现
鸭子的哪些功能会根据需求变化?叫声、飞行...
Duck类:
package com.qiuyang.duck;
import com.qiuyang.strategy.behaviorInter.FlyBehavior;
import com.qiuyang.strategy.behaviorInter.QuackBehavior;
import com.qiuyang.strategy.behaviorInter.SwimBehavior;
public abstract class Duck {
protected FlyBehavior flyBehavior;
protected QuackBehavior quackBehavior;
protected SwimBehavior swimBehavior;
public void fly(){
flyBehavior.fly();
}
public void quack(){
quackBehavior.quack();
}
public void swim(){
swimBehavior.swim();
}
public abstract void display();
}
Duck的子类:
package com.qiuyang.duck;
import com.qiuyang.strategy.behaviorImpl.FastSwimBehavior;
import com.qiuyang.strategy.behaviorImpl.FlyOKBehavior;
import com.qiuyang.strategy.behaviorImpl.GoodQuackBehavior;
public class GreenHeadDuck extends Duck{
public GreenHeadDuck(){
this.flyBehavior = new FlyOKBehavior();
this.swimBehavior = new FastSwimBehavior();
this.quackBehavior = new GoodQuackBehavior();
}
@Override
public void display() {
System.out.println("green head duck!");
}
}
Main类:
package com.qiuyang.main;
import com.qiuyang.duck.Duck;
import com.qiuyang.duck.GreenHeadDuck;
import com.qiuyang.duck.RedHeadDuck;
public class Main {
public static void main(String[] args) {
Duck gd = new GreenHeadDuck();
Duck rd = new RedHeadDuck();
gd.fly();
gd.swim();
gd.quack();
rd.fly();
rd.swim();
rd.quack();
}
}
优点:新增行为简单,行为类更好的复用,组合更方便。如fly()方法各种鸭子表现不同,但又只有会飞和不会飞两种,故将行为fly抽象为借口,用两个实现类来表示会飞与不会飞,Duck类持有借口的引用,其子类GreenHeadDuck将超类中的引用实例化为会飞。新增一个子行为飞得慢,只需要再增加一个子类SlowFlyBehavior即可,以后新类(老鸭)在初始化flyBehavior引用时用new SlowFlyBehavior()即可,不会影响原来Duck/GreenHeadDuck/RedHeadDuck等类(添加fly的具体下属方式(飞的快慢)不会影响这些类,添加一个行为如跳跃这些会带来一点影响)。
5.模式总结
创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。
StrategyPatternDemo,我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化
public interface Strategy {
public int doOperation(int num1, int num2);
}
//***********************************
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
//**********************************
public class OperationSubstract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
//*********************************
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
//********************************
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
//使用 Context 来查看当它改变策略 //Strategy 时的行为变化。
//StrategyPatternDemo.java
//************************************
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubstract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
//*********************************
//输出:
//10 + 5 = 15
//10 - 5 = 5
//10 * 5 = 50