策略模式
定义:该模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法得变化不会影响使用算法得客户,策略模式属于对象行为模式。通过对算法得封装,把使用算法得责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理
策略模式主要角色结构如下所示:
抽象策略类:这是一个抽象对象,通常由一个接口或者抽象类来实现,此角色给出所有的具体策略类所需的接口
具体策略类:实现了抽象策略定义的接口,提供具体的算法实现或行为
环境类:持有策略类的引用,最终给客户端调用
案例实现
促销活动,一家百货公司在定年度的促销活动,针对不同的节日(春节,中秋节,端午节)推出不同的促销活动,由促销员将促销活动展示给客户。
代码实现:
定义抽象策略接口,规范了各个节假日所推出的促销活动,具体促销活动留给子类实现
public interface Strategy { void show(); }
定义具体策略类,春节促销活动
public class StrategyA implements Strategy{ @Override public void show() { System.out.println("春节活动,买一送一"); } }
定义具体策略类,中秋节促销活动
public class StrategyB implements Strategy{ @Override public void show() { System.out.println("中秋节活动,满200减100"); } }
定义具体策略类,端午节促销活动
public class StrategyC implements Strategy{ @Override public void show() { System.out.println("端午节活动,满300减200"); } }
定义环境类,促销员类,其中包含所有具体策略类的引用,对外提供统一访问方法,根据节假日不同选择不同的促销活动
public class SalesMan { private final Map<String,Strategy> strategyMap=new HashMap<>(3); public SalesMan(){ StrategyA strategyA=new StrategyA(); StrategyB strategyB=new StrategyB(); StrategyC strategyC=new StrategyC(); strategyMap.put("春节",strategyA); strategyMap.put("中秋节",strategyB); strategyMap.put("端午节",strategyC); } public void show(String festivalName){ Strategy festival=strategyMap.get(festivalName); festival.show(); } }
测试类,测试策略模式的使用
public class Test { public static void main(String[] args) { SalesMan salesMan=new SalesMan(); salesMan.show("春节"); } }
策略模式优缺点
优点
策略类之间可以自由切换,由于策略类都实现同一个接口,所以使得他们可以自由切换
易于扩展,增加一个新的策略只需要添加一个具体的策略类即可,基本不需要修改原有的代码。符合开闭原则,避免使用多重if else语句,充分体现面向对象设计思想
缺点
客户端必须知道所有策略类,并自行决定使用哪一个策略类
策略模式将会产生很多策略类,可以通过享元模式在一定程度上减少对象的数量
策略模式适用场景
一个系统需要动态的在几种算法中选择一种时,可将每个算法封装到策略类中
一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入他们各自的策略类中以代替这些分支语句
系统中各算法彼此完全独立,且要求对客户隐藏具体的实现细节时
系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构
多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为