策略模式定义了一系列算法,把它们一个个封装起来,并且使它们可相互替换。该模式可使得算法能独立于使用它的客户而变化。
Strategy模式是行为模式,正因为他是一种行为模式,所以他不是用来解决类的实例化的,跟创建什么样的产品没有关系,此模式解决的问题是把一个系列完成相同工作,却实现不同的算法(行为)包装到一系列的策略类里面,使得它们可以相互替换,提供一个访问接口,由客户端决定在什么情况下使用什么具体策略,来完成某一功能。并可以自由的添加修改相应的算法,轻松实现可插入式(Pluggable)的系统的开发。对于客户端来说,不关心实例化了那些对象,生产了那些产品,只需要提供要使用那种策略去完成某一功能。
例子:商品打折
a.商品策略:分图书、衣服...
b.打折策略:高级会员打8折,中级打9折,普通不打折
1.新建一个商品接口,封装获取价格的方法;图书、衣服实现该Goods接口
public interface Goods { public double getPrice(); }
public class Goods_Book implements Goods{ @Override public double getPrice() { return 40; } }
public class Goods_Clothes implements Goods{ @Override public double getPrice() { return 200; } }
2.新建一个打折策略接口,封装计算某商品价格的方法;各个会员打折策略类实现该接口
public interface StrategyInterface { /** * 计算商品价格 * @param goods * @return */ double culPrice(Goods goods);//接口中的方法默认public }
/** * 高级会员 打折策略 * @author Administrator * */ public class StrategyA implements StrategyInterface { @Override public double culPrice(Goods goods) { System.out.println("高级会员,打8折"); return goods.getPrice() * 0.8; } }
/** * 中级会员 打折策略 * @author Administrator * */ public class StrategyB implements StrategyInterface { @Override public double culPrice(Goods goods) { System.out.println("中级会员,打9折"); return goods.getPrice() * 0.9; } }
/** * 普通会员 打折策略 * @author Administrator * */ public class StrategyC implements StrategyInterface { @Override public double culPrice(Goods goods) { System.out.println("普通会员,不打折"); return goods.getPrice(); } }
3.新建一个Price类,定义商品策略和打折策略,然后根据这2个策略进行计算价格
public class Price { private Goods goods;//商品种类 private StrategyInterface strategy;//打折策略 public Price(Goods goods, StrategyInterface strategy) { this.goods = goods; this.strategy = strategy; } /** * 根据商品种类和打折策略计算折后价格 * @return */ public double culPrice(){ return this.strategy.culPrice(goods); } }
4.写客户端(Test类)调用策略
/** * 策略模式: * 并不决定在何时使用何种算法。 * 在什么情况下使用什么算法是由客户端(即Test类)决定的。 * @author Administrator * */ public class Test { public static void main(String[] args) { //定义何种商品和策略 // Goods goods = new Goods_Book(); Goods goods = new Goods_Clothes(); StrategyInterface strategy = new StrategyA(); // StrategyInterface strategy = new StrategyB(); // StrategyInterface strategy = new StrategyC(); System.out.println("原价:"+goods.getPrice()+",折后价:"+new Price(goods, strategy).culPrice()); } }
5.查看结果
高级会员,打8折
原价:200.0,折后价:160.0
中级会员,打9折
原价:200.0,折后价:180.0
...
jdk中的这些实现都用到了策略模式
- java.util.Comparator#compare()
- javax.servlet.http.HttpServlet
- javax.servlet.Filter#doFilter()
总结:引自:http://www.cnblogs.com/java-my-life/archive/2012/05/10/2491891.html
策略模式的重心
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。
所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。
运行时策略的唯一性
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
公有的行为
经常见到的是,所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。当然这时候抽象策略角色必须要用Java抽象类实现,而不能使用接口。
这其实也是典型的将代码向继承等级结构的上方集中的标准做法。
策略模式的优点
(1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
(2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。
策略模式的缺点
(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。