1.前言:

这是策略模式在spring中的使用,对策略模式不了解对同学可以移步在商城中简单对使用策略模式

2.问题:

在策略模式中,我们创建表示各种策略的对象和一个行为,随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

在spring 中,策略对象在正常情况下是,在启动Spring容器对时候,已经将策略对象加载创建完成成为bean。

我们如何在Spring中正确对使用策略模式,这样又会发生什么问题呢?

3.使用场景: 

场景:商城活动中有几种,满减,打折,送积分.我们要获取商品对最终价格。

4.实现

步骤一.创建接口类

public interface GoodsActivity {

    /**
* 获取应该支付的金额
* @param amount 商品的单价
* @return
*/
BigDecimal getPayPrice(BigDecimal amount); }

步骤二.实现接口,并添加@Component注解

@Component
public class DiscountActivity implements GoodsActivity { //折扣
private double discount ; @Override
public BigDecimal getPayPrice(BigDecimal amount) { //假装从数据库的配置表取折扣
discount = 8.0; return new BigDecimal(discount).multiply(amount).divide(new BigDecimal(10));
}
}
@Component
public class FullReduceActivity implements GoodsActivity { //满多少
private BigDecimal fullAmount; //减多少
private BigDecimal reductionAmount ; @Override
public BigDecimal getPayPrice(BigDecimal amount) { //假装从数据库的配置表取配置数据
fullAmount = new BigDecimal(300); reductionAmount = new BigDecimal(100); return amount.compareTo(fullAmount)>=0?amount.subtract(reductionAmount):amount;
}
}
@Component
public class IntegralActivity implements GoodsActivity { //抵扣的积分 10积分=1元
private int integral = 100; @Override
public BigDecimal getPayPrice(BigDecimal amount) {
return amount.subtract(new BigDecimal(integral/10));
}
}

步骤三.创建context

public class GoodsActivityContext {

    private GoodsActivity goodsActivity;

    public GoodsActivityContext(GoodsActivity goodsActivity){
this.goodsActivity=goodsActivity;
} /**
* 获取商品价格
* @param amount
* @return
*/
public BigDecimal getPrice(BigDecimal amount){
return goodsActivity.getPayPrice(amount);
} }

步骤四.在控制层中调用策略模式

@RestController
public class ActivityController{ @Autowired
private DiscountActivity discountActivity; @Autowired
private FullReduceActivity fullReduceActivity; @Autowired
private IntegralActivity integralActivity; /**
* 获取最终售价
* (这样的控制层写法很不友好,需要写大量的代码去实现)
* 为了解决这个问题,将引用工厂模式...
*
* 工厂是创建型模式,它的作用就是创建对象;
* 策略是行为型模式,它的作用是让一个对象在许多行为中选择一种行为;
*
* 解决不同的问题
* 工厂模式是创建型的设计模式,它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等。
* 策略模式是为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。
*
* 工厂相当于黑盒子,策略相当于白盒子;
*
*
* @param activityType
* @param amount
* @return
*/
@RequestMapping("getLastPrice")
public ResponseResult getLastPrice(String activityType,BigDecimal amount){ ResponseResult responseResult = ResponseResult.getInstance(); GoodsActivityContext goodsActivityContext; //根据活动类型获取最终售价
switch (activityType){
case "discount":
goodsActivityContext = new GoodsActivityContext(discountActivity);
break;
case "fullReduce":
goodsActivityContext = new GoodsActivityContext(fullReduceActivity);
break;
case "integral":
goodsActivityContext = new GoodsActivityContext(integralActivity);
break;
default:
responseResult.setCode(1);
responseResult.setMsg("数据类型错误");
responseResult.setData(null);
return responseResult;
} responseResult.setCode(0);
responseResult.setMsg("操作成功");
responseResult.setData(goodsActivityContext.getPrice(amount)); return responseResult;
} }

总结:按照注释说明,很明显我们需要优化这个策略模式。

步骤三:(2) 引入工厂模式,对策略对象进行管理

@Component
public class GoodsActivityStrategyFactory { @Autowired
private Map<String,GoodsActivity> goodsActivityMap; /**
* 根据活动类型 获取所对应的策略
* @param activityType
*/
public GoodsActivityContext getGoodsActivityStrategy(String activityType){ GoodsActivityContext goodsActivityContext; switch (activityType){
case "discount":
goodsActivityContext = new GoodsActivityContext(goodsActivityMap.get("discountActivity"));
break;
case "fullReduce":
goodsActivityContext = new GoodsActivityContext(goodsActivityMap.get("fullReduceActivity"));
break;
case "integral":
goodsActivityContext = new GoodsActivityContext(goodsActivityMap.get("integralActivity"));
break;
default:
goodsActivityContext = null;
} return goodsActivityContext;
} }

步骤四.在控制层中调用策略模式

@RestController
public class ActivityController{ @Autowired
private GoodsActivityStrategyFactory goodsActivityStrategyFactory; @RequestMapping("getLastPrice_V2")
public ResponseResult getLastPrice_V2(String activityType,BigDecimal amount){ ResponseResult responseResult = ResponseResult.getInstance();
//从工厂中获取 活动策略
GoodsActivityContext goodsActivityContext = goodsActivityStrategyFactory.getGoodsActivityStrategy(activityType); if (goodsActivityContext==null){
responseResult.setCode(1);
responseResult.setData(null);
responseResult.setMsg("数据类型错误");
return responseResult;
} responseResult.setCode(0);
responseResult.setMsg("操作成功");
responseResult.setData(goodsActivityContext.getPrice(amount)); return responseResult; }
}

源码:

在springboot中使用策略模式

在工作中,不能灵活的时候设计模式。希望通过这次的学习,可以加深对设计模式对理解。

接下来会继续整理出自己在工作对时候可以使用对设计模式,不对望指点。如果文章对您有帮助,github给个start吧。

在商城系统中使用设计模式----策略模式之在spring中使用策略模式的更多相关文章

  1. 设计模式_策略模式_在Spring中的应用

    一.理论 在spring中经常有读取配置文件的需求,这里就会用到一个Spring提供的Resource接口 Resource 接口是具体资源访问策略的抽象,也是所有资源访问类所实现的接口.Resour ...

  2. ssh下:系统初始化实现ServletContextListener接口时,获取spring中数据层对象无效的问题

    想要实现的功能:SSH环境下,数据层都交由Spring管理:在服务启动时,将数据库中的一些数据加载到ServletContext中缓存起来. 系统初始化类需要实现两个接口: ServletContex ...

  3. spring中bean的五种作用域?Spring中的bean是线程安全的吗?

    spring中bean的五种作用域 当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域.Spring支持如下5种作用域: singleto ...

  4. Spring中单例模式中的饿汉和懒汉以及Spring中的多例模式

    链接:https://pan.baidu.com/s/1wgxnXnGbPdK1YaZvhO7PDQ 提取码:opjr 单例模式:每个bean定义只生成一个对象实例,每次getBean请求获得的都是此 ...

  5. 访何红辉:谈谈Android源码中的设计模式

    最近Android 6.0版本的源代码开放下载,刚好分析Android源码的技术书籍<Android源码设计模式解析与实战>上市,我们邀请到它的作者何红辉,来谈谈Android源码中的设计 ...

  6. (转)Spring中Singleton模式的线程安全

    不知道哪里的文章,总结性还是比较好的.但是代码凌乱,有的还没有图.如果找到原文了可以进行替换! spring中的单例 spring中管理的bean实例默认情况下是单例的[sigleton类型],就还有 ...

  7. spring 中常用的设计模式

    一. Spring 中常见的设计模式 工厂模式 : BeanFactory 装饰器模式: BeanWrapper 代理模式: AopProxy 单例模式: ApplicationContext 委派模 ...

  8. Spring 中使用了那些设计模式呢?

    一. Spring 中常见的设计模式 工厂模式 : BeanFactory 装饰器模式: BeanWrapper 代理模式: AopProxy 单例模式: ApplicationContext 委派模 ...

  9. Tomcat 系统架构与设计模式

    Tomcat 系统架构与设计模式,第 1 部分: 工作原理 这个分为两个部分的系列文章将研究 Apache Tomcat 的系统架构以及其运用的很多经典设计模式.本文是第 1 部分,将主要从 Tomc ...

随机推荐

  1. 快速排序 JavaScript 实现

    作为算法目录下的第一篇博文,快速排序那是再合适不过了.作为最基本最经典的算法之一,我觉得每个程序员都应该熟悉并且掌握它,而不是只会调用库函数,知其然而不知其所以然. 排序算法有10种左右(或许更多), ...

  2. C#控件之:进度条(ProgressBar)

    一.重绘进度条 public class CustomProgressBar:ProgressBar { public CustomProgressBar() { this.SetStyle(Cont ...

  3. chrome用type=file获取图片路径并转base64字符串

    1 html页面 <div class="col-sm-2" style="height: 200px;margin-top: 14px;"> &l ...

  4. 第十四个目标 (fzu)

    http://acm.fzu.edu.cn/contest/problem.php?cid=151&sortid=8 Problem Description 目暮警官.妃英里.阿笠博士等人接连 ...

  5. Beta阶段第五篇Scrum冲刺博客-Day4

    1.站立式会议 提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 张晨晨:目标增加单词收藏功能 郭琪容:学习收藏功能的实 ...

  6. POJ1064--Cable master(Binary Search)

    Description Inhabitants of the Wonderland have decided to hold a regional programming contest. The J ...

  7. 二分搜素——(lower_bound and upper_bound)

    因为每个人二分的风格不同,所以在学习二分的时候总是被他们的风格搞晕.有的人二分风格是左闭右开也就是[L,R),有的人是左开右闭的(L,R]. 二分的最基本条件是,二分的序列需要有单调性. 下面介绍的时 ...

  8. poj 2676 如何填满九宫格

    Sudoku Time Limit: 2000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java class ...

  9. Android-Java-等待唤醒机制原理

    儿时的游戏:(等待 与 唤醒) 有一群小朋友一起玩一个游戏,这个游戏可能大家都玩过,大家一起划拳,划拳输得最惨的那个小朋友去抓人(这个小朋友取名为 CPU),被抓的很多人取名为线程,有很多线程,如果其 ...

  10. [转载]腾讯专家:论高级DBA的自我修养

    作者介绍: 张秀云:2007年开始从事运维方面的工作,经历过网络管理员.linux运维工程师.DBA.分布式存储运维等多个IT职位.对linux运维.mysql数据库.分布式存储有丰富的经验.2012 ...