java设计模式---策略模式(案例解析)

qdhxhz      2022-05-06     190

关键词:

策略模式

一、概念

1、理解策略模式

策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口具体行为的实现。策略模式最大的特点是行为的变化,行为之间可以相互替换。

每个if判断都可以理解为就是一个策略。

2、策略模式特点

策略模式把对象本身和行为区分开来,因此我们整个模式也分为三个部分。

1、抽象策略类(Strategy):策略的抽象,行为方式的抽象
2、具体策略类(ConcreteStrategy):具体的策略实现,每一种行为方式的具体实现。
3、环境类(Context):用来封装具体行为,操作策略的上下文环境。

3、举例理解(打车)

这里举个简单的例子,来理解开发中运用策略模式的场景。

有一个打车软件,现在有三种计费模式给 用户 选择,1、拼车 2、快车 3、豪车这个时候用户就是对象,三种计费方式就是行为,可以根据不同的行为计算不同不通的值。

1)传统实现方式

代码

    /**
      * @Description: 这里只展示计费最终费用示例
      *
      * @param  type 计费类型
      * @param  originalPrice 原始价格
      */
    public Double calculationPrice(String type, Double originalPrice) {

        //拼车计费
        if (type.equals("pc")) {
            return originalPrice * 0.5;
        }
        //快车计费
        if (type.equals("kc")) {
            return originalPrice * 1;
        }
        //豪车计费
        if (type.equals("hc")) {
            return originalPrice * 2;
        }
        return originalPrice;
    }

传统的实现方式,通过传统if代码判断。这样就会导致后期的维护性非常差。当后期需要新增计费方式,还需要在这里再加上if(),也不符合设计模式的开闭原则。

2)策略模式实现

抽象策略类

/**
 * 出行策略接口
 */
public interface PriceStrategy {
	/**
	 * @param originalPrice 原始价格
	 * @return  计算后的价格
	 */
	Double countPrice(Double originalPrice);
}

具体策略实现类

/**
  * @Description: 拼车的计费方式
  */
public class PcStrategy implements PriceStrategy {
    @Override
    public Double countPrice(Double originalPrice) {
        return originalPrice * 0.5;
    }
}

/**
  * @Description: 快车的计费方式
  */
public class KcStrategy implements PriceStrategy {
    @Override
    public Double countPrice(Double originalPrice) {
        return originalPrice * 1;
    }
}

/**
  * @Description: 拼车的计费方式
  */
public class HcStrategy implements PriceStrategy {
    @Override
    public Double countPrice(Double originalPrice) {
        return originalPrice * 2;
    }
}

环境类

也叫做上下文类或环境类,起承上启下封装作用。

/**
 * 负责和具体的策略类交互
 * 这样的话,具体的算法和直接的客户端调用分离了,使得算法可以独立于客户端独立的变化。
 * 如果使用spring的依赖注入功能,还可以通过配置文件,动态的注入不同策略对象,动态的切换不同的算法.
 */
public class PriceContext {

    /**
     * 出行策略接口
     */
    private PriceStrategy riceStrategy;
    /**
     * 构造函数注入
     */
    public PriceContext(PriceStrategy riceStrategy) {
        this.riceStrategy = riceStrategy;
    }
    /**
     * 计算价格
     */
    public Double countPrice(Double originalPrice) {
        return riceStrategy.countPrice(originalPrice);
    }
}

测试类

    public static void main(String[] args) {
        //具体行为策略
        PriceStrategy pcStrategy = new PcStrategy();
        PriceStrategy kcStrategy = new KcStrategy();
        PriceStrategy hcStrategy = new HcStrategy();

        //用户选择不同的策略
        PriceContext pcContext = new PriceContext(pcStrategy);
        PriceContext kcContext = new PriceContext(kcStrategy);
        PriceContext hcContext = new PriceContext(hcStrategy);

        System.out.println("拼车价格 = " +  pcContext.countPrice(10D));
        System.out.println("快车价格 = " +  kcContext.countPrice(10D));
        System.out.println("豪车价格 = " +  hcContext.countPrice(10D));
    }

运行结果

拼车价格 = 5.0
快车价格 = 10.0
豪车价格 = 20.0

整理流程就是这个样的,这里有一点需要注意 我在做测试的时候具体策略对象都是new出来,而实际运用应该通过spring来管理,这样才能做到真正的开闭原则。下面会在举例。

4、策略模式优缺点

优点

1)避免使用多重条件判断

如果没有策略模式,一个策略家族有多个策略算法,一会要使用A策略,一会要使用B策略,怎么设计呢?使用多重if的条件语句?多重条件语句不易维护,而且出错的概率大大增强。

使用策略模式后,简化了操作,同时避免了条件语句判断。

2)扩展性良好

在现有的系统中增加一个策略太容易了,只要实现接口就可以了,其他都不用修改,类似于一个可反复拆卸的插件,这大大地符合了OCP原则。

缺点

1)策略类数量增多

策略模式一个明显的缺点是当备用行为过多时,行为对象会非常庞大

5、策略模式运用场景

通过上面的优缺点我们可以很好的去思考,什么场景下可以考虑用策略模式?

我的理解就是:每个if判断都可以理解为就是一个策略。按理说都可以采用策略模式,但是如果if else里面的逻辑不多,且复用性很低,那就不需要。如果if里面的行为比较大

而且这些行为复用性比较高就可以考虑通过采用策略模式。

在我们生活中比较常见的应用模式有:

1、电商网站支付方式,一般分为银联、微信、支付宝,可以采用策略模式
2、电商网站活动方式,一般分为满减送、限时折扣、包邮活动,拼团等可以采用策略模式

二、策略模式实战示例

最近正在做到电商项目,因为有多个活动,所以我就考虑用策略模式来实现。我们活动分为很多种满减送,包邮活动,限时折扣等等,这里大致写下对于多个活动如何去使用策略模式。

1、Order实体

活动是跟订单绑定在一起的,只有下了单才去计算这个订单走了哪个活动。

/**
  * @Description: 订单实体
  */
public class Order {
    /**
     * 用户ID
     */
    private Long userId;
    /**
     * 订单编号
     */
    private String orderNumber;
    /**
     * 购买数量
     */
    private Integer goodsNumber;
    /**
     * 订单运费
     */
    private Double orderFreight;
    /**
     * 订单总价(订单价格 + 运费)
     */
    private Double orderPrice;
    /**
     * 活动类型 1、包邮 2、满减送 3、限时折扣
     */
    private String activityType;
    /**
     * 活动ID
     */
    private String activityId;
  //省略get set方法

2、ActivityStrategy(活动策略接口)

/**
 * 定义一个总的活动抽象
 */
public interface ActivityStrategy {

    /**
     * 定义一个我们优惠活动的价格算法方法
     */
    Order calculate (Order order);
}

3、具体活动策略实现类

FreeShippingActivity 包邮

/**
  * @Description: 包邮活动
  */
@Component
@Service("freeShippingActivity")
public class FreeShippingActivity implements ActivityStrategy {
    @Override
    public Order calculate(Order order) {
        //包邮活动是一个大的主题 ,里面可以创建很多小活动 比如价格满100包邮活动,或者满2件以上包邮活动,江浙沪包邮活动等等
        //如果这里通过活动ID获取用户具体选择了哪一个活动。
        String activityId = order.getActivityId();
        //查询数据库
        System.out.println("模拟查询数据库 ,当前的活动是满100包邮");
        order.setOrderFreight(0.0D);
        return order;
    }
}

FullDeliveryActivity (满减送活动)

/**
  * @Description: 满减送活动
  */
@Component
@Service("fullDeliveryActivity")
public class FullDeliveryActivity implements ActivityStrategy {
    @Override
    public Order calculate(Order order) {
        //如果这里通过活动ID获取用户具体选择了哪一个活动。
        String activityId = order.getActivityId();
        //查询数据库
        System.out.println("模拟查询数据库 ,当前的活动是满100减20的");
        if (order.getOrderPrice() > 100) {
            order.setOrderPrice(order.getOrderPrice() - 20);
        }
        return order;
    }
}

LimitDiscountActivity (限时折扣活动)

/**
  * @Description: 限时折扣活动
  */
@Component
@Service("limitDiscountActivity")
public class LimitDiscountActivity implements ActivityStrategy {
    @Override
    public Order calculate(Order order) {
        //如果这里通过活动ID获取用户具体选择了哪一个活动。
        String activityId = order.getActivityId();
        //查询数据库
        System.out.println("模拟查询数据库 ,当前的活动是截至2020.10.1前 打9折");
            order.setOrderPrice(order.getOrderPrice() * 0.9);

        return order;
    }
}

3、环境类

/**
 * 负责和具体的策略类交互 动态的切换不同的算法
 */
@Component
public class ActivityContext {

    @Autowired
    private FreeShippingActivity freeShippingActivity;

    @Autowired
    FullDeliveryActivity fullDeliveryActivity;

    @Autowired
    LimitDiscountActivity limitDiscountActivity;

    /**
     * 出行策略接口
     */
    private final Map<String, ActivityStrategy> activityStrategyMap = new HashMap();
  
    /**
     * 初始化 把这几个活动的示例 初始化的时候就装到一个map集合中
     */
    @PostConstruct
    public void init() {
        //1、包邮 2、满减送 3、限时折扣
        activityStrategyMap.put("1", freeShippingActivity);
        activityStrategyMap.put("2", fullDeliveryActivity);
        activityStrategyMap.put("3", limitDiscountActivity);
    }

    /**
     * 计算价格
     */
    public Order calculate(Order order) {
        ActivityStrategy activityStrategy = activityStrategyMap.get(order.getActivityType());
        return activityStrategy.calculate(order);
    }
}

4、测试类

@RestController
public class PayController {

    @Autowired
    private ActivityContext activityContext;

    @RequestMapping("/test")
    public  Object test(){
        Order order = new Order();
        //1 代表包邮
        order.setActivityType("1");
        //具体活动ID
        order.setActivityId("12");
        //总价
        order.setOrderPrice(200D);
        //运费
        order.setOrderFreight(10D);
        return activityContext.calculate(order);
    }
}
//输出: 模拟查询数据库 ,当前的活动是包邮

总结 这里我们没有用到if else来判断用户到底选择了哪个活动类型,而是通过先把所有活动的bean实体装入一个map中,然后通过activityType 来获取具体是哪个活动类型。

以后新添加一个活动,比如拼团活动,我们只需做两步

1、新建一个拼团活动策略类 实现总策略接口 2、activityStrategyMap中put这个折扣活动的bean实体。

除了map管理bean外,还有一种方式就是可以通过spring来管理这些具体的策略类

//freeShippingActivity 这个值可以在数据库添加一张表来管理,然后来读取 这样的话新建活动只需要做上面的第一步,代码更加好维护了。
ActivityStrategy payStrategy= SpringUtils.getBean("freeShippingActivity", ActivityStrategy.class);

这里只是列了个架构,实际开发中比这个复杂多了,因为可以同时选择多个活动,活动于活动之间又会有互斥关系。


参考

1、策略模式

2、支付平台选择(策略模式)

3、Java设计模式-策略模式



``` 别人骂我胖,我会生气,因为我心里承认了我胖。别人说我矮,我就会觉得好笑,因为我心里知道我不可能矮。这就是我们为什么会对别人的攻击生气。 攻我盾者,乃我内心之矛(8)。 ```

设计模式课程设计模式精讲19-3策略模式源码解析(代码片段)

1    源码解析1.1    源码解析1(jdk中的应用1)1.2    源码解析2(jdk中的应用2)1.3    源码解析3(Spring中的应用1)1.4    源码解析4(Spring中的应用2)   1    源码解析1.1    源码解... 查看详情

策略模式的案例(代码片段)

...0c;一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的context对象。策略对象改变context对象的执行算法。介绍... 查看详情

设计模式案例

1.策略模式package策略模式;publicclassConcreteStrategyextendsStrategy{ publicvoidstrategyInteface(){ //TODOAuto-generatedmethodstub }}package策略模式;publicclassContex{ privateStrategystrategy; publicvoidcontex 查看详情

设计模式——策略模式

一、策略模式案例一二、策略模式案例二:实现表单验证普通的表单验证功能实现:使用策略模式实现: 查看详情

设计模式——策略模式

一、策略模式案例一二、策略模式案例二:实现表单验证普通的表单验证功能实现:使用策略模式实现: 查看详情

设计模式——策略模式

一、策略模式案例一二、策略模式案例二:实现表单验证普通的表单验证功能实现:使用策略模式实现: 查看详情

设计模式之策略模式(代码片段)

策略模式就是提供一组固定算法的策略,客户根据自己的需求选择其中一种策略进行执行。特点:预先明确的一组固定算法策略客户需要选择其中一种策略场景:网络爬虫,针对不同的网站,预先提供不同的解析算法网站预先提... 查看详情

策略模式经典案例排序算法(代码片段)

...策略模式策略模式(StrategyPattern)是一种行为型设计模式,它定义了一系列算法,将每个算法都封装起来,并且使它们可以相互替换。策略模式可以让算法的变化独立于使用它们的客户端,从而提高了系统... 查看详情

c++策略模式的具体案例与优缺点(代码片段)

  策略模式:准备一组算法,并将每一个算法封装起来,使得它们可以互换。1、策略模式中的角色与职责  在策略模式中分为4个角色:环境类Context、具体环境类SubContext、策略类Stategy、具体策略类SubStrategy。... 查看详情

c++策略模式的具体案例与优缺点(代码片段)

  策略模式:准备一组算法,并将每一个算法封装起来,使得它们可以互换。1、策略模式中的角色与职责  在策略模式中分为4个角色:环境类Context、具体环境类SubContext、策略类Stategy、具体策略类SubStrategy。... 查看详情

java设计模式——策略模式(代码片段)

1、简介策略模式(StrategyPattern)是一种比较简单的模式,也叫做政策模式(PolicyPattern)。其定义如下:Defineafamilyofalgorithms,encapsulateeachone,andmaketheminterchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互... 查看详情

经典案例python详解设计模式:策略模式(代码片段)

完成一项任务往往有多种方式,我们将其称之为策略。比如,超市做活动,如果你的购物积分满1000,就可以按兑换现金抵用券10元,如果购买同一商品满10件,就可以打9折,如果如果购买的金额超过500,就可以享受满减50元的优... 查看详情

设计模式:策略模式(代码片段)

设计模式:策略模式特点案例:购物车结算完整代码特点一个问题匹配多个解决方案可以添加解决方案可以删除解决方案案例:购物车结算解决方案constsale='100_10':price=>price-=10,'200_30':price=>... 查看详情

设计模式---策略模式(代码片段)

...f0c;每一条途径对应一种算法,此时我们可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增加新的解决途径。策略模式包含角色Contex 查看详情

设计模式-策略模式strategy以及消灭ifelse

概述  如果在开发过程中,出现大量的ifelse或者switchcase语句,如果这些语句块中的代码并不是包含业务逻辑,只是单纯的分流方法,那么,每一个语句块中都是一个算法或者叫策略。背景   比如在最近项目中遇到的问... 查看详情

java设计模式—策略模式

  在阎宏博士的《JAVA与模式》一书中开头是这样描述策略(Strategy)模式的:  策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模... 查看详情

java设计模式之策略模式

    策略模式属于对象的行为模式,策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换,策略模式让算法独立于使用它的客户而独立变化。策略模式使这些算法在客户端调用它们... 查看详情

设计模式:helloworld之策略模式

一.概述策略模式定义了算法族,分别封装起来,让他们可以互相替换,此模式让算法的变化独立于使用算法的客户。策略模式的三要素:抽象策略角色:策略类,通常由一个接口或者抽象类实现。具体策略角色:包装了相关的... 查看详情