狐言不胡言

导航

诸葛亮的锦囊妙计竟然是大名鼎鼎的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:所有的策略类都需要对外暴露
下面看下类图:
在这里插入图片描述
涉及到的角色:

  1. 环境(Context)角色:持有一个Stratogy类的引用
  2. 抽象策略(Strategy)角色:这是一个抽象角色,通常有一个接口或抽象类实现,此角色给出了所有具体的策略类所需要的接口
  3. 具体策略(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个的时候,就需要考虑使用混合模式了,避免策略类膨胀

posted on 2021-04-17 10:28  狐言不胡言  阅读(146)  评论(0编辑  收藏  举报