如有转载,请申明:
转载至 http://blog.csdn.net/qq_35064774/article/details/51960311
1 什么是策略模式?
策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
生活中有很多需要策略模式的例子,举个比较简单的。某购物网站,需要针对某些书进行打折促销,但不同书的打折策略不一定相同。对教材类的书每本减免10元,对连环画采用每本优惠%7,其他图书没有优惠。
这时候我们需要对不同的对象采用不同的策略。
2 怎么用策略模式?
我们以一个问题入手。
* 现有一个超市,针对不同商品有不同的打折方案
* 春季打折,享受8折商品:优质西瓜、香蕉
* 周年放价,享受7折商品:普通西瓜、苹果
首先我们定义一个计算优惠后的价格的接口。
package com.ittianyu.strategy;
public interface DiscountScheme {
float getDiscountedPrice(Goods goods);
String getName();
}
然后我们定义商品类
package com.ittianyu.strategy;
public class Goods {
private String name;
private float originalPrice;
DiscountScheme discountScheme = new SpringDiscount();// strategy
public Goods(String name, float originalPrice) {
super();
this.name = name;
this.originalPrice = originalPrice;
}
public Goods(String name, float originalPrice, DiscountScheme discountScheme) {
super();
this.name = name;
this.originalPrice = originalPrice;
this.discountScheme = discountScheme;
}
public float getOriginalPrice() {
return originalPrice;
}
public void setOriginalPrice(float originalPrice) {
this.originalPrice = originalPrice;
}
public void setDiscountScheme(DiscountScheme discountScheme) {
this.discountScheme = discountScheme;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// strategy
public float getPrice() {
return discountScheme.getDiscountedPrice(this);
}
public String getDiscountScheme() {
return discountScheme.getName();
}
}
商品类里面定义了一个接口的对象,然后再getDiscountedPrice和getDiscountScheme方法中,调用了接口中的方法。
你问我为什么是这样?不要方,继续往下看。
接下来我们定义两个个具体的策略,也就是具体的打折方案。
package com.ittianyu.strategy;
public class SpringDiscount implements DiscountScheme {
@Override
public float getDiscountedPrice(Goods goods) {
return goods.getOriginalPrice() * 0.8f;
}
@Override
public String getName() {
return "春季打折";
}
}
package com.ittianyu.strategy;
public class AnnualDiscount implements DiscountScheme {
@Override
public float getDiscountedPrice(Goods goods) {
return goods.getOriginalPrice() * 0.7f;
}
@Override
public String getName() {
return "周年放价,全部7折";
}
}
我们姑且定义一个春季打折和周年打折方案。
接下来是用着这些类的时候了。
为了承载众多物品,我们还需要一个容器类。
定义一个Market类,支持添加、删除和遍历商品。
package com.ittianyu.strategy;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
public class Market {
private Collection<Goods> collection = new LinkedList<Goods>();
public void add(Goods goods) {
collection.add(goods);
}
public void remove(Goods goods) {
collection.remove(goods);
}
public Iterator<Goods> iterator() {
return collection.iterator();
}
}
最后,终于可以测试了,我们定义一个启动类。
package com.ittianyu.strategy;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
Market market = new Market();
market.add(new Goods("西瓜", 1.0f));
market.add(new Goods("西瓜", 1.0f, new AnnualDiscount()));
market.add(new Goods("苹果", 2.0f, new AnnualDiscount()));
market.add(new Goods("香蕉", 1.5f));
Iterator<Goods> iterator = market.iterator();
while (iterator.hasNext()) {
Goods goods = iterator.next();
System.out.println(goods.getName() + " 原价" +
goods.getOriginalPrice() + " " +
goods.getDiscountScheme() + " 现价" + goods.getPrice());
}
}
}
输出结果为:
西瓜 原价1.0 春季打折 现价0.8
西瓜 原价1.0 周年放价,全部7折 现价0.7
苹果 原价2.0 周年放价,全部7折 现价1.4
香蕉 原价1.5 春季打折 现价1.2
到此不知道你是否理解了策略模式。
简单来说就是把算法实现和使用分离了。我们使用的时候,还是需要手动指定使用哪种策略,但我们很好的分离了算法的使用和实现。我们实现的时候,不必考虑怎么使用,使用的时候,不用考虑他是怎么实现的。而且可以动态的切换算法。
3 在什么情况下使用策略模式
* 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
* 一个系统需要动态地在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体算法类,并只持有一个数据类型是抽象算法类的对象。
* 一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端涉及到不必要接触到的复杂的和只与算法有关的数据。
* 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念。
4 策略模式的优点和缺点
优点:
* 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
* 策略模式提供了可以替换继承关系的办法。
* 使用策略模式可以避免使用多重条件转移语句。
缺点:
* 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别以便适时选择恰当的算法类。
* 策略模式造成了很多的策略类。