简介
策略模式(Strategy Pattern)隶属于设计模式中的行为型模式,是日常开发中使用最广的一个模式,相对于其他模式,自认为这个模式是最容易理解和使用的。
策略模式:定义一系列的算法,把他们封装起来,并使得他们可相互替换,使得算法可独立于使用的客户而变化。
策略模式中的策略在定义中被表述为算法,并不是只有我们在算法导论中学习到的才是算法,这里的算法是一个更广泛的含义,意为解决一个问题采用的步骤。在排序中,要解决的问题是对元素排序,快排、插排、冒泡排等是解决问题的不同策略;实际生活中,商场对如何对产品定价是一个问题,新老客户使用不同的折扣,大促与平常使用不同的折扣也是策略。
策略模式有三个角色:上下文、抽象策略接口、具体策略实现。
策略模式中核心就是策略接口和策略实现,可以看到策略模式从本质上来说就是对继承和多态的使用,不同的策略实现之间也要遵循里氏替换原则,不过策略模式的不同策略实现之间还有其他约束,我们后面在看。
各个网站现在都在上线会员服务,不同的会员在购买产品时所享受的价格是不一样的,会员会有不同的等级、积分,在很多服务上也会区分不同的会员,我们就以会员购买产品时可以使用的折扣来说明策略模式。
假设我们是电商网站,网站根据用户的积分分为正常用户,青铜会员,黄金会员,不同的会员在买产品时可以享受不同的折扣。如果不使用策略模式,那么对每一个类型的用户我们都需要使用 if else
来区分,面向过程的解决方法如下:
public class Website {
public static void main(String[] args) {
String memberType = args[0];
// 原价
float price = 100;
// 黄金会员打7 折
if ("1".equals(memberType)) {
price *= 0.7;
} else if ("2".equals(memberType)) {
// 青铜会员打八折
price *= 0.8;
} else {
// 正常用户打9折
price *= 0.9
}
//收费
System.out.println(price);
}
}
如果是再来一个钻石会员,那么就要修改网站里的这一堆if else 代码,违反了开闭原则,而且价格的计算细节直接放到网站中也不符合单一职责原则,因此我们使用策略模式来重写计算逻辑。
public interface Discount {
public float discount();
}
// 正常折扣
public class NormalDiscount implements Discount {
public float discount() {
return 0.9f;
}
}
//青铜折扣
public class BronzeDiscount implements Discount {
public float discount() {
return 0.8f;
}
}
// 黄金折扣
public class GoldDiscount implements Discount {
public float discount {
return 0.7f;
}
}
由于这里的策略模式比较简单,我们不写上下文对象,而是使用简单工厂模式来根据会员类型生成折扣策略实例。
public class SimpleDiscountFactory {
private static Map<String, Discount> discountMap = new HashMap<>();
static {
discountMap.put("1", new GoldDiscount());
discountMap.put("2", new BronzeDiscount());
}
public Discount getDiscount(String memeberType) {
Class<Discount> discount = discountMap.get(memberType);
if (discount != null) {
return discount;
}
// 默认返回正常折扣
return new NormalDiscount();
}
}
public class Website {
public static void main(String[] args) {
String memberType = args[0];
// 原价
float price = 100;
Discount discount = SimpleDiscountFactory.getDiscount(memberType);
price *= discount.discount();
//收费
System.out.println(price);
}
}
如果需要增加会员类型,那么只需要实现一个新的折扣类型就可以了,在这里我们只是简单的使用原价乘以折扣的方式来计算付费价格,日常中的计价计算会更复杂,可能不同的会员都会有一套计算逻辑,那么此时可以将计算价格的步骤抽象出来成为策略。策略的范围是由具体的问题复杂度来决定的。
策略模式在日常中经常使用,有时可能我们都没有意识到,符合上面所说的三个条件的场景都可以使用策略模式,我们列一下日常具体的场景: