23种设计模式(二)---策略设计模式

简介: 23种设计模式(二)---策略设计模式

策略设计模式---透彻讲解


一. 什么是策略设计模式



设计模式有三种:创建型, 行为型, 结构型. 策略设计模式属于行为型. 为什么属于行为型呢? 来看看下面解释:


1.1 什么是策略呢?


什么是策略呢?


举个例子: 出行方式: 可以骑自行车, 摩托车, 开小汽车, 坐公交车, 坐火车, 轮船, 飞机等等. 这些出行方式都是出行的策略.


再来看商场搞促销: 打8折, 打7折, 满100减30, 购物满500返现50等等, 无论何种打折方式, 其根本都是算法, 这些算法就是一种策略. 策略之间是可以随机互换的. 比如同一件商场,今天可以打8折, 明天可以满100件30.


策略设计模式: 定义【一组】算法, 将【每个】算法进行包装, 并且他们之间可以随意【互换】, 来看一下UML图:

969a22456c9a449aa93a52ab1a262f2f_tplv-k3u1fbpfcp-zoom-1.png


从上图可以看出, 定义一个策略设计模式需要4大步骤

  1. 策略接口类: 是对策略, 算法的抽象. 定义了每个策略和算法必须有的算法和属性.
  2. 策略实现类: 策略,算法的具体实现. 策略具体有几种类型的实现就定义几个策略类,并实现策略方法
  3. Context上下文类: Context上下文, 起到承上启下的作用. 屏蔽了上层模块对策略,算法的访问, 封装了可能存在的变化.
    到底当前要调用那个策略, 通过定义构造函数传参决定, 策略方法可以没有入参, 但必须有构造方法, 构造方法决定类的实际策略. 可扩展性强, 增加新的策略, 不需要动用老代码.
  4. 客户端类: 客户端调用Context上下文类, 并指定要调用策略的类. 所以, 就要求用户提前知道有哪些策略类.

以上就是策略设计模式实现的4步骤


二. 策略设计模式代码实现


我们就以商场促销为例, 使用策略设计模式来实现.

现在商场要促销, 商品促销方式有: 原价, 折扣(8折, 7折), 满减(满100减30, 满100减20)等. 具体的促销方式就是策略.

根据实现的4个步骤, 一步一步来实现


2.1 第一步: 定义商场促销的接口类


package com.lxl.www.designPatterns.strategy;
/**
 * 促销类
 */
public interface IPromotionStrategy {
    /**
     * 促销
     *
     * 入参是原价, 出参是促销价格
     * @return
     */
    Double promotion(PromotionVo promotionVo) throws Exception;
}

这里定义了一个促销策略的接口类. 并定义了促销方案.


2.2 第二步: 促销方案的实现类


促销方案一共有3种: 第一种:原价, 第二种: 打折 第三种: 满减


先来看看第一种: 原价

package com.lxl.www.designPatterns.strategy;
/**
 * 正常售卖价格
 */
public class CommonPromotionStrategy implements IPromotionStrategy {
    @Override
    public Double promotion(PromotionVo promotionVo) {
        return promotionVo.getOriginPrice();
    }
}

原价也就是正常售卖的价格. 所以, 没有任何计算逻辑

第二种, 打折

package com.lxl.www.designPatterns.strategy;
/**
 * 打折
 */
public class DiscountPromotionStrategy implements IPromotionStrategy {
    @Override
    public Double promotion(PromotionVo promotionVo) throws Exception {
        if (promotionVo.getDiscount() < 0 || promotionVo.getDiscount() >=1 ){
            throw new Exception("请输入正确的折扣");
        }
        return promotionVo.getOriginPrice() * promotionVo.getDiscount();
    }
}

打折有折扣, 那么折扣必须是0-1范围, 并且最后返回折后价

第三种. 满减

package com.lxl.www.designPatterns.strategy;
/**
* 满减折扣
*/
public class FullReductionPromotionStrategy implements IPromotionStrategy {
   /**
    * 满减
    * @return
    * @throws Exception
    */
   @Override
   public Double promotion(PromotionVo promotionVo) throws Exception {
       if (promotionVo.getReduction() == null || promotionVo.getFull() == null) {
           throw new Exception("请检查满减参数");
       }
       Double price = promotionVo.getOriginPrice();
       Double canPromotionPrice=promotionVo.getOriginPrice();
       while(canPromotionPrice >= promotionVo.getFull()) {
           price = price - promotionVo.getReduction();
           canPromotionPrice -= promotionVo.getFull();
       }
       return price;
   }
}

这里实现 满减逻辑是每满100减30, 要是300就减90.


2.3 第三步: context商场促销类


我们商场里的商品到底是什么样的优惠方案呢? 有商场促销类决定

package com.lxl.www.designPatterns.strategy;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * 商场促销
 */
public class MallPromotion {
    @Autowired
    private IPromotionStrategy promotion;
    public MallPromotion(IPromotionStrategy promotion) {
        this.promotion = promotion;
    }
    public Double activityPromotion(PromotionVo promotionVo) throws Exception {
        return this.promotion.promotion(promotionVo);
    }
}

促销类定义了一个构造函数, 用来指定当前的促销方案.


2.4 具体商品的实际促销方案


public static void main(String[] args) throws Exception {
        PromotionVo promotionVo = new PromotionVo(300.0, 0.8, 100.0, 30.0);
        System.out.println("<br><br>==========正常售卖=========");
        MallPromotion mallPromotionContext1 = new MallPromotion(new CommonPromotionStrategy());
        System.out.println(mallPromotionContext1.activityPromotion(promotionVo));
        System.out.println("<br><br>==========8折=========");
        MallPromotion mallPromotionContext2 = new MallPromotion(new DiscountPromotionStrategy());
        System.out.println(mallPromotionContext2.activityPromotion(promotionVo));
        System.out.println("<br><br>==========满100减30=========");
        MallPromotion mallPromotionContext3 = new MallPromotion(new FullReductionPromotionStrategy());
        System.out.println(mallPromotionContext3.activityPromotion(promotionVo));
    }
}

我们想要什么样 促销方案都是可以的. 只需要调用商场促销类并传入促销策略即可.


三. 策略设计模式的应用



3.1 什么时候使用?


一个系统有许多类,而他们之间的区别是: 行为的不同. 这时候可以使用策略设计模式.

3.2 优点


  1. 策略模式提供了对 “开闭原则” 的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
  2. 算法可以互相切换, 无需知道算法的具体实现
  3. 使用策略模式可以避免多重条件选择语句。多重条件选择语句是硬编码,不易维护。
  4. 可扩展性更好, 可以灵活地增加新的算法或行为。也可灵活切换算法或者行为


3.3 缺点


  1. 使用策略设计模式会产生很多具体策略类, 客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类来完成剩余功能的情况。
  2. 所有的策略类需要对外暴露. 因为客户端只有知道有哪些策略, 才知道应该是用哪个.这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。


4. 使用场景


1、一个系统, 需要动态的在几个算法之间选择, 它们之间的区别仅仅是算法或者行为的不同,那么可以使用策略模式, 这样我们可以动态地让一个对象在许多行为中选择一种行为。

2、一个系统需要动态地在几种算法中选择一种。

3、一个对象有很多的行为,如果不用策略设计模式,这些行为就只好使用多重条件选择语句来实现。而使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句。


5. 注意事项


如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。


四. 策略设计模式结合工厂设计模式的应用



上面的商场促销活动. 最终策略都要暴露给客户端, 这对客户端来说不是特别友好. 我们可以结合简单工厂设计模式, 将策略进行封装.


package com.lxl.www.designPatterns.strategy;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * 商场促销
 */
public class MallPromotionContext {
    @Autowired
    private IPromotionStrategy promotion;
    public MallPromotionContext(IPromotionStrategy promotion) {
        this.promotion = promotion;
    }
    public MallPromotionContext(Integer type) {
        switch (type) {
            case 1:
                this.promotion = new CommonPromotionStrategy();
                break;
            case 2:
                this.promotion = new DiscountPromotionStrategy();
                break;
            case 3:
                this.promotion = new FullReductionPromotionStrategy();
                break;
        }
    }
    public Double activityPromotion(PromotionVo promotionVo) throws Exception {
        return this.promotion.promotion(promotionVo);
    }
}

这样封装以后的好处就是, 客户端只需要知道自己要什么类型的促销策略, 而不用关注具体促销策略类型.


下面来看一下策略代码的实现


public static void main(String[] args) throws Exception {
        PromotionVo promotionVo = new PromotionVo(300.0, 0.8, 100.0, 30.0);
        System.out.println("<br><br>==========正常售卖=========");
        MallPromotionContext mallPromotionContext1 = new MallPromotionContext(1);
        System.out.println(mallPromotionContext1.activityPromotion(promotionVo));
        System.out.println("<br><br>==========8折=========");
        MallPromotionContext mallPromotionContext2 = new MallPromotionContext(2);
        System.out.println(mallPromotionContext2.activityPromotion(promotionVo));
        System.out.println("<br><br>==========满100减30=========");
        MallPromotionContext mallPromotionContext3 = new MallPromotionContext(3);
        System.out.println(mallPromotionContext3.activityPromotion(promotionVo));
    }


在基本的策略设计模式中, 选择所用具体实现的职责有客户端对象承担, 并转给策略模式的Context对象, 并没有减轻客户端需要选择判断的压力.而策略设计模式与简单工厂设计模式的结合, 选择具体实现的则在有也由Context来承担, 这就大大的减轻了客户端的职责.


相关文章
|
7月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
145 0
|
7月前
|
设计模式 编解码 C++
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用(一)
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用
202 0
|
7月前
|
设计模式 存储 缓存
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用(二)
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用
116 0
|
2月前
|
设计模式 监控 算法
Java设计模式梳理:行为型模式(策略,观察者等)
本文详细介绍了Java设计模式中的行为型模式,包括策略模式、观察者模式、责任链模式、模板方法模式和状态模式。通过具体示例代码,深入浅出地讲解了每种模式的应用场景与实现方式。例如,策略模式通过定义一系列算法让客户端在运行时选择所需算法;观察者模式则让多个观察者对象同时监听某一个主题对象,实现松耦合的消息传递机制。此外,还探讨了这些模式与实际开发中的联系,帮助读者更好地理解和应用设计模式,提升代码质量。
Java设计模式梳理:行为型模式(策略,观察者等)
|
7月前
|
设计模式 监控 Java
设计模式 - 观察者模式(Observer):Java中的战术与策略
【4月更文挑战第7天】观察者模式是构建可维护、可扩展系统的关键,它在Java中通过`Observable`和`Observer`实现对象间一对多的依赖关系,常用于事件处理、数据绑定和同步。该模式支持事件驱动架构、数据同步和实时系统,但需注意避免循环依赖、控制通知粒度,并关注性能和内存泄漏问题。通过明确角色、使用抽象和管理观察者注册,可最大化其效果。
127 2
|
4月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
56 1
|
5月前
|
设计模式 安全 Java
Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
118 0
|
7月前
|
设计模式 Java
设计模式之策略 Strategy
设计模式之策略 Strategy
46 1
|
设计模式 算法 搜索推荐
设计模式—策略(Strategy)模式
设计模式—策略(Strategy)模式
154 1
|
7月前
|
设计模式 缓存 安全
分析设计模式对Java应用性能的影响,并提供优化策略
【4月更文挑战第7天】本文分析了7种常见设计模式对Java应用性能的影响及优化策略:单例模式可采用双重检查锁定、枚举实现或对象池优化;工厂方法和抽象工厂模式可通过对象池和缓存减少对象创建开销;建造者模式应减少构建步骤,简化复杂对象;原型模式优化克隆方法或使用序列化提高复制效率;适配器模式尽量减少使用,或合并多个适配器;观察者模式限制观察者数量并使用异步通知。设计模式需根据应用场景谨慎选用,兼顾代码质量和性能。
57 0