诸葛亮的锦囊妙计竟然是大名鼎鼎的Java设计模式:策略模式
应用场景
京东、天猫双十一,情人节商品大促销,各种商品有不同的促销活动
- 满减:满200减50
- 每满减:每满100减10
- 打折:买两件8折,三件7折
- 数量减:满三件减去最低价的一件
顾客在下单的时候可以选择其中几种来剁手,那么后端怎么来灵活的应对金额的计算呢,以后可能不同的节日还会有更多的促销活动,该怎么去计算订单的金额?
简单实现例子
public class OrderService {
public Order OrderPrices(Order order, String promotion) {
if (promotion.equals("promotion-1")) {
//计算金额
} else if (promotion.equals("promotion-2")) {
//计算金额
}
switch (promotion) {
case "promotion-1" :
//计算金额
break;
case "promotion-2" :
//计算金额
break;
}
return order;
}
}
上述的这种使用if else或者switch case方式并没有什么问题,但是促销活动会有很多种,这样的话,if else或者switch case里面的内容就会很多,那么怎么改进呢
也许会想到,每一种促销手段单独拿出来就会好一些,基于这个方法的设计原则:就是单一职责原则
public class OrderService {
public Order OrderPrices(Order order, String promotion) {
if (promotion.equals("promotion-1")) {
calPromotion1(order);
} else if (promotion.equals("promotion-2")) {
calPromotion2(order);
}
switch (promotion) {
case "promotion-1" :
calPromotion1(order);
break;
case "promotion-2" :
calPromotion2(order);
break;
}
return order;
}
public Order calPromotion1(Order order) {
return order;
}
public Order calPromotion2(Order order) {
return order;
}
}
上面的改进虽然好了一些,但是促销活动是不断变化的,一变化就需要修改OrderService类,而OrderService类是关于订单的,希望能够少改动,而不断变化的是促销算法
分析一下就可以知道,这里变化的是同一个行为的不同算法,那么再次改进
改进代码
同一行为的不同算法实现,我们可以用接口来定义行为,不同的算法分别去实现接口
设计原则:对修改关闭,对扩展开放
public interface PromotionAlgorithm {
Order promotionAlgorithm(Order order);
}
public class PromotionAlgorithm1 implements PromotionAlgorithm {
@Override
public Order promotionAlgorithm(Order order) {
System.out.println("满200减50");
return order;
}
}
public class PromotionAlgorithm2 implements PromotionAlgorithm {
@Override
public Order promotionAlgorithm(Order order) {
System.out.println("满2件打8折");
return order;
}
}
public class OrderService {
public Order OrderPrices(Order order, String promotion) {
if (promotion.equals("promotion-1")) {
return new PromotionAlgorithm1().promotionAlgorithm(order);
} else if (promotion.equals("promotion-2")) {
return new PromotionAlgorithm2().promotionAlgorithm(order);
}
switch (promotion) {
case "promotion-1" :
return new PromotionAlgorithm1().promotionAlgorithm(order);
case "promotion-2" :
return new PromotionAlgorithm2().promotionAlgorithm(order);
}
return order;
}
}
把每一种促销算法单独实现,然后使用,这就是策略模式的应用
类图:
策略模式
定义
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的用户而独立变化
意图
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替
主要解决问题
在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护
何时使用
一个系统有许多类,而区分它们的只是他们直接的行为
优缺点
优点:
1:各种算法可以随意切换
2:可以避免使用多重判断引起的麻烦
3:扩展性好
缺点:
1:策略类比较多
2:所有的策略类都需要对外暴露
下面看下类图:
涉及到的角色:
- 环境(Context)角色:持有一个Stratogy类的引用
- 抽象策略(Strategy)角色:这是一个抽象角色,通常有一个接口或抽象类实现,此角色给出了所有具体的策略类所需要的接口
- 具体策略(ConcreteStartegy)角色:包装了相关的算法或者行为
Context类:
public class Context {
private Strategy strategy;
/** 策略方法 */
public void contextInterface() {
strategy.strategyInterface();
}
}
Strategy类:
public interface Strategy {
/** 策略方法 */
void strategyInterface();
}
ConcreteStrategy类:
public class ConcreteStrategy implements Strategy{
/** 策略方法 */
@Override
public void strategyInterface() {
//do something
}
}
诸葛亮的锦囊妙计
当年赵云保护刘备入吴国迎娶美女,诸葛亮给了他三个锦囊,囊中有三个妙计,嘱咐赵云见机行事。这三个锦囊妙计是很符合策略模式的,看来诸葛亮不是策略模式的的始作俑者也是最初的实践者,下面是一个小例子:
锦囊妙计接口:
public interface SeminalVesicle {
/** 按计行事 */
String tricks();
}
按计行事实现类:
public class BackDoor implements SeminalVesicle {
/** 按计行事 */
@Override
public String tricks() {
return "走乔国老的后门";
}
}
public class GoBack implements SeminalVesicle {
/** 按计行事 */
@Override
public String tricks() {
return "骗刘备回去";
}
}
public class Retreat implements SeminalVesicle {
/** 按计行事 */
@Override
public String tricks() {
return "请孙夫人退兵";
}
}
赵云类:
public class ZhaoYun {
private SeminalVesicle seminalVesicle;
public ZhaoYun(SeminalVesicle seminalVesicle) {
this.seminalVesicle = seminalVesicle;
}
/** 按计行事 */
public String act() {
return seminalVesicle.tricks();
}
}
测试类:
public class Test {
public static void main(String[] args) {
ZhaoYun zhaoYun = new ZhaoYun(new Retreat());
System.out.println("赵云按计行事");
System.out.println(zhaoYun.act());
}
}
类图:
需要注意的是,如果策略比较多,差不多多于4个的时候,就需要考虑使用混合模式了,避免策略类膨胀