思考问题:
一个书店的某类书是免费的,某类书是固定1元的,某类书是按折扣算的(比如88%)(同一类别的书本价格一样)。假定顾客只买一类书,在设计书店BookStore类时应该如何计算顾客买书的费用?
解答:
1. 你有可能不知道如何设计,毕竟上面的计算规则不一样(并不是一类书8折另一类书9折那样好计算);
2. 既然这样,我们就定义一个接口(策略接口),规定一个方法(strategyInterface())为计算金额的方法,BookStore类构造对象时传入该策略接口的实现类对象(在构造该对象时告诉它买多少本书,单价多少钱),那么调用该接口的方法即可获得计算好的金额。
上面实例的代码就不编了,给出一个通用的策略模式模板吧:
抽象策略类(用于规定策略类的策略方法签名):
package com.shusheng.srategy;
/**抽象策略类*/
public abstract class Strategy {
//策略方法
public abstract void strategyInterface();
}
具体策略实现类:
package com.shusheng.srategy;
/**具体策略实现类*/
public class ConcreteStrategy1 extends Strategy{
/**具体策略函数*/
@Override
public void strategyInterface() {
System.out.println("我是具体策略1,我将执行算法1");
}
}
具体策略类2:
package com.shusheng.srategy;
/**具体策略*/
public class ConcreteStrategy2 extends Strategy {
/**策略函数*/
@Override
public void strategyInterface() {
System.out.println("我是具体策略2,我将执行算法2");
}
}
上下文类(上下文角色,作用:封装策略模式,避免外界直接调用策略类的方法)
package com.shusheng.srategy;
/**上下文类(上下文角色)*/
public class Context {
public Strategy strategy;//策略对象的引用
public Context(Strategy strategy) {//构造函数,构造上下文对象时要初始化策略对象
this.strategy = strategy;
}
/**调用策略,比如这个就是BookStore的计算金额的方法*/
public void contextInterface(){//暴露给外界的方法,避免外界直接调用策略模式内部方法(如strategyInterface()就是策略模式内部的)
this.strategy.strategyInterface();
}
}
测试类:
package com.shusheng.srategy;
public class StrategyTest {
public static void main(String[] args) {
Context context = new Context(new ConcreteStrategy1());//初始化上下文对象时也要初始化策略类对象
context.contextInterface();//调用上下文对象的方法而不是直接调用策略对象内部的方法
Context context2 = new Context(new ConcreteStrategy2());//初始化上下文对象时也要初始化策略类对象
context2.contextInterface();//调用上下文对象的方法而不是直接调用策略对象内部的方法
}
}
策略模式优点:
1. 策略模式提供了管理相关的算法族的办法。(外界不需要知道内部是怎么实现的,只需要调用Context类的方法即可)
2. 使用策略模式可以避免使用多重条件if-else语句,实现细节:定义一个策略类接口(规定好策略方法),将if内部代码封装为一个策略实现类的方法,else内部代码也封装为另一个策略实现类的方法。(假设含if-else语句的类为Context),Context类中使用到if-else的地方直接替换为调用策略接口类的策略方法,当构造Context时传入具体的策略对象即可。这样在原先调用if-else的地方就会调用策略类的方法。
策略模式缺点:
1. 正如优点中对if-else的解说,客户端类必须知道哪一个策略类的具体功能是什么的,才能传入正确的策略对象,这意味着:别人使用该接口是必须理解这些策略算法的区别;即策略模式只适用于客户知道所有的算法或行为的情况。
2. 使用策略模式会造成很多的策略类,正如if-(else if) - (else if) -(else if) -else这样,就会产生很多策略类(每种情况一个类)。当然也可以用享元模式来减少对象的数量。
策略模式 的应用场景:
1. 多个类只是在算法或行为上稍有不同的场景(就可以把不同的算法或行为部分提取出来设计成策略模式)
2. 算法需要自由切换的场景
3. 需要屏蔽算法规则的场景(就是策略函数内部实现是屏蔽的,外界只是调用Context的方法)