策略模式
定义
定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
解决
在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。实现某一个功能有多个途径,此时可以使用该模式来使得系统可以灵活地选择解决途径,也能够方便地增加新的解决途径。
优点
- 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。(算法可以自由切换且扩展性良好)
- 使用策略模式可以避免使用多重条件转移语句。
缺点
- 客户端必须知道所有的策略类(类需要对外暴露),并自行决定使用哪一个策略类。
- 策略模式将造成产生很多策略类。
结构
策略模式包含如下角色:
- Context: 环境类
- Strategy: 抽象策略类
- ConcreteStrategy: 具体策略类
实现
package strategymethod;
/**
* Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用
*/
//上下文
public class Context {
Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
/**
* 上下文接口
*/
public void contextInterface() {
strategy.algorithmInterface();
}
}
package strategymethod;
/**
* Strategy类,定义所有支持的算法的公共接口
*/
//接口
public interface Strategy{
//算法方法
public void algorithmInterface();
}
/**
* ConcreteStrategy类封装了具体的算法或行为,实现类Strategy接口
*/
//具体算法A
class ConcreteStrategyA implements Strategy{
@Override
public void algorithmInterface()
{
System.out.println("算法A实现");
}
}
//具体算法B
class ConcreteStrategyB implements Strategy{
@Override
public void algorithmInterface()
{
System.out.println("算法B实现");
}
}
//具体算法C
class ConcreteStrategyC implements Strategy{
@Override
public void algorithmInterface()
{
System.out.println("算法C实现");
}
}
package strategymethod;
public class StrategyClient {
public static void main(String[] args) {
Context context;
//由于实例化不同的策略,所以得出的方法也不同
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
}
}
实例
商场中搞促销活动,有三种情况:原价,打折,返利:
package strategymethod.demo;
//现金收费接口
public interface CashSuper {
//方法
public double acceptCash(double money);
}
//正常收费子类,原价返回
class CashNormal implements CashSuper {
@Override
public double acceptCash(double money)
{
return money;
}
}
//打折收费子类
class CashDiscount implements CashSuper {
private double discount;
public CashDiscount(double discount)
{
this.discount=discount;
}
@Override
public double acceptCash(double money)
{
return money*discount;
}
}
//返利收费子类
class CashReturn implements CashSuper {
//in case:满300 减50这种
private double condition;
private double moneyReturn;
public CashReturn(double condition,double moneyReturn)
{
this.condition=condition;
this.moneyReturn=moneyReturn;
}
@Override
public double acceptCash(double money)
{
double result=0;
if(money>=condition)
result=money-(Math.floor(money/condition)*moneyReturn);
return result;
}
}
package strategymethod.demo;
public class CashContext {
CashSuper cs;
public CashContext(CashSuper cs) {
this.cs = cs;
}
/**
* 上下文接口
*/
public double getResult(double money) {
return cs.acceptCash(money);
}
}
package strategymethod.demo;
public class CashClient {
public static void main(String[] args) {
CashContext cashContext;
double Cash;
//由于实例化不同的策略,所以得出的方法也不同
cashContext = new CashContext(new CashNormal());
Cash=cashContext.getResult(500);
System.out.println(Cash);
cashContext = new CashContext(new CashDiscount(0.7));
Cash=cashContext.getResult(500);
System.out.println(Cash);
cashContext = new CashContext(new CashReturn(300,50));
Cash=cashContext.getResult(500);
System.out.println(Cash);
}
}
总结
- 在策略模式中定义了一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式。策略模式是一种对象行为型模式。
- 策略模式包含三个角色:环境类在解决某个问题时可以采用多种策略,在环境类中维护一个对抽象策略类的引用实例;接口为所支持的算法声明了抽象方法,是所有策略类的父类;具体策略类实现了在接口中定义的算法。
- 策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。
- 策略模式主要优点在于对“开闭原则”的完美支持,在不修改原有系统的基础上可以更换算法或者增加新的算法,它很好地管理算法族,提高了代码的复用性,是一种替换继承,避免多重条件转移语句的实现方式;其缺点在于客户端必须知道所有的策略类,并理解其区别,同时在一定程度上增加了系统中类的个数,可能会存在很多策略类。
- 策略模式适用情况包括:在一个系统里面有许多类,它们之间的区别仅在于它们的行为,使用策略模式可以动态地让一个对象在许多行为中选择一种行为;一个系统需要动态地在几种算法中选择一种;避免使用难以维护的多重条件选择语句;希望在具体策略类中封装算法和与相关的数据结构。