一.策略模式概述
针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使他们可以相互替换。
目的:使算法在不影响客户端的情况下发生改变
二. 策略模式角色
1.抽象策略角色(strategy):是一个抽象的角色,通常由一个接口或抽象类实现
2.具体策略角色(concreteStrategy):包装了相关的算法或行为
3.环境角色(context):持有一个stategy的引用。
三.策略模式例子
某商场推出会员模式,根据不同的历史消费记录分为普通用户,会员,超级会员,黄金会员,根据会员类型的不同,打折的力度也不同。
解决方案1:使用继承
使用继承可能是最容易想到的,就是在打折系统的服务端程序中实现各种打折方案,然后客户端继承服务端,作为子类去调用父类中的代码,从而实现了代码的复用。但要考虑到,这个系统可能不是为一个商场用的,不同的商场可能有不同的打折方案,这样客户端直接继承服务端的方案明显是不可行的
解决方案2:使用策略模式
由于不同商场可能有不同的打折方案,这样我们可以把不同的打折方案分离出来,独立成类,实现打折接口,客户端可以直接决定使用哪个策略完成支付,在Context类中提供一个计算最终价格的统一接口,客户端只需要调用这个Context类的计算最终结果的方法就可以实现功能
(1)策略接口
public interface CalPrice {
//根据原价返回一个最终的价格
Double calPrice(Double orgnicPrice);
}
(2)策略实现
public class Orgnic implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice;
}
}
public class Vip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.9;
}
}
public class SuperVip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.8;
}
}
public class GoldVip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.7;
}
}
(3)环境
public class Price {
//持有一个具体的策略对象
private CalPrice calprice;
//构造函数
public Price(CalPrice calPrice){
this.calPrice = calPrice;
}
//计算客户最终要付的钱
public Double calLastAmount(amount) {
return calPrice.calPrice(amount);
}
}
(4)客户端
public class Client {
public static void main(String[] args) {
//1.客户端决定要使用的策略
private Double totalAmount = 0D;//客户在消费的总额
private Double amount = 0D;//客户单次消费金额
private CalPrice stategy= new Orgnic();//默认初始为普通用户
//客户购买,就会增加它的总额 并选出要使用的策略
public void buy(Double amount) {
this.amount = amount;
totalAmount += amount;
if (totalAmount > 30000) {//30000则改为金牌会员计算方式
calPrice = new GoldVip();
} else if (totalAmount > 20000) {//类似
calPrice = new SuperVip();
} else if (totalAmount > 10000) {//类似
calPrice = new Vip();
}
}
//2.创建环境
Price price = new Price(stategy);
//3.计算价格
double quote = price. calLastAmount(300);
}
四.优缺点
优点:增强了可扩展性,提供了一个管理算法族的办法,新增加的算法并不会影响到其它的算法
缺点:客户端必须知道所有的策略类并且自行决定使用哪个策略类(可以使用工厂方法模式改进,传送:)