前情提要

上集讲到, 小光引入了饮料机(工厂方法模式)改进了光氏饮品的生产过程. 现在如果要新上什么饮品, 改变配方什么的, 都很简单了, 直接增加一个饮料机, 或是替换/拿掉一个饮料机就可以了. 表妹再也不抱怨了.

小光也找了些饮料厂商拿到了一些试喝的饮料新品. 心想, 正好临近感恩节, 圣诞节, 双十二啥的, 我可以拿这些饮料新品来做些活动啊, 感恩下新老顾客啊... 这些新品小光可是自己亲身试喝过的, 绝对好喝, 小光不做奸商, :)

所有示例源码已经上传到Github, 戳这里

活动策划

小光以其独特的码农生意人思维(我也不知道这是什么...), 很快想出了几条活动方案:

  • 即日起, 到感恩节(11/24)那天, 所有饮品6折优惠.
  • 双十二当天, 满12立减2元.
  • 12月20号到圣诞节(12/25), 买热干面+饮料套餐送大苹果.

小光想出这些活动方案后, 屁颠屁颠去拿给表妹看. 没曾想, 表妹一脸不愉快, 这么多方案, 还这么负责, 我怎么记得住...(单细胞的表妹).

怎么办了, 小光可不想放弃自己好不容易想出的这些方案, 而且活动方案肯定会因为是不同节日而有所改变嘛.

解决之道

很快, 小光就想到了解决办法, 他将三种活动方案的算法做好, 内置在收银台. 在不同的日子里选用不用的算法策略.

"我真是个天才, 哈哈哈哈", 小光想着都快笑出声了...

照例, 收银员无需关注是什么具体的算法, 故而抽象出一个父级接口:

public interface ActivityStrategy {String getActivityPrice();
}复制代码

每个方案对应一个算法策略:

// 感恩节活动算法
public class ThanksGivingDayStrategy implements ActivityStrategy {@Overridepublic String getActivityPrice() {// 经过一系列算法return "(感恩节)所有饮品一律5折";}
}// 双十二算法
public class DoubleTwelveDayStrategy implements ActivityStrategy {@Overridepublic String getActivityPrice() {// 经过一系列算法return "(双十二)满12立减2元";}
}// 圣诞节算法
public class ChristmasStrategy implements ActivityStrategy {@Overridepublic String getActivityPrice() {// 经过一系列算法return "(圣诞节)买热干面+饮品套餐, 送大苹果一个";}
}// 默认算法(注意这个, 稍后的扩展阅读会说下这个Default实现的意义)
public class DefaultActivityStrategy implements ActivityStrategy {@Overridepublic String getActivityPrice() {// 什么都不做return "没有活动";}
}复制代码

支持各种活动策略算法的收银台:

// 收银台
public class Checkstand {private ActivityStrategy mActivityStrategy;public Checkstand() {mActivityStrategy = new DefaultActivityStrategy();}public Checkstand(ActivityStrategy activityStrategy) {this.mActivityStrategy = activityStrategy;}public void setActivityStrategy(ActivityStrategy activityStrategy) {this.mActivityStrategy = activityStrategy;}public void printBill() {System.out.println("本次账单活动:" + mActivityStrategy.getActivityPrice());}
}复制代码

投入使用

活动方案算法和收银台完工之后, 小光立马投入了使用:

public class XiaoGuang {public static void main(String[] args) {// 收银台, 默认Checkstand checkstand = new Checkstand();checkstand.printBill();// 感恩节期间checkstand.setActivityStrategy(new ThanksGivingDayStrategy());checkstand.printBill();// 双十二checkstand.setActivityStrategy(new DoubleTwelveDayStrategy());checkstand.printBill();// 圣诞节期间checkstand.setActivityStrategy(new ChristmasStrategy());checkstand.printBill();}
}复制代码

结果, 也正如小光预料的:

本次账单活动:没有活动
本次账单活动:(感恩节)所有饮品一律5折
本次账单活动:(双十二)满12立减2元
本次账单活动:(圣诞节)买热干面+饮品套餐, 送大苹果一个复制代码

活动一经推出, 顾客果然是比以前更多了...
大家还对小光新推出的那些试喝饮料赞不绝口, 都觉得味道不错, 还很着很有意思的名字...

故事之后

照例, 故事之后, 我们用UML类图来梳理下上述的关系(关注收银台与活动策略算法之间的关系):

大家可能已经看出端倪了, 没错, 这就是策略模式.

策略模式(Strategy Pattern):
定义一组算法, 并将每一个单独算法封装起来, 让它们可以相互替换.

策略模式让算法独立于使用它的客户而变化, 例如如果明年小光的双十二活动改变了, 只需单独修改这个DoubleTwelveDayStrategy即可, 客户类(收银台Checkstand)无需改变, 也无需关注每个算法的具体实现.

扩展阅读一

实际上策略模式也还是利用抽象, 封装, 继承, 多态的面向对象特性, 来达到封装变化, 解耦合的. 典型的开闭原则的实践.

另外, 眼尖的同学可能看到, 貌似这个类图似曾相识啊. 前面讲的简单工厂和工厂方法中的类图与此极其相似:

比较上图三个模式的红框部分, 我们可以发现, 相当一致. 在此明确下三者的关系与区别:

  1. 首先简单工厂工厂方法创建型的模式, 而策略模式行为型的模式.
  2. 所谓创建型就是说用来生产对象的, 注重的生产(new)这个部分, 用创建型的模式来代替直接new一个实例, 更多是想将直接的实例依赖通过不同的方法转化接口依赖.
  3. 所谓行为型模式更多是描述一种行为, A使用B, 怎么使用的这个关系上.

实际上, 在上个工厂方法的故事中, 我们就已经使用到了策略模式.

表妹选择不同的饮料机来那饮料, 这个行为实际上就是一个策略模式的体现, 回顾下表妹的代码:

public class Cousins {private IBeverageMachine mBeverageMachine;private void setBeverageMachine(IBeverageMachine machine) {this.mBeverageMachine = machine;}private Drink takeDrink() {if (mBeverageMachine == null) throw new NullPointerException("Should set Beverage Machine firstly.");return mBeverageMachine.makeDrink();}public static void main(String[] args) {Cousins cousins = new Cousins();// for Acousins.setBeverageMachine(new OrangeJuiceMachine());Drink drink = cousins.takeDrink();System.out.println(drink);// for Bcousins.setBeverageMachine(new CokeMachine());System.out.println(cousins.takeDrink());// for Dcousins.setBeverageMachine(new MilkTeaMachine());System.out.println(cousins.takeDrink());}
}复制代码

和我们这个收银台(Checkstand)是一样一样的, 上例中的模式使用实际可以理解成是这样:

  • 蓝色部分是工厂方法模式的使用, 作用在于生产出不同的饮品.
  • 红色部分是策略模式的使用, 作用在于让表妹根据实际情况选择不同的饮料机.

所以说模式的运用, 往往不是简单而单一, 很多时候是很多模式合在一起的.

扩展阅读二

在展示本例策略模式的UML类图时, 我们将DefaultActivityStrategy类标记成红色了, 这是为什么呢?

是因为这里我们用的这个DefaultActivityStrategy实际上也是一种设计模式的体现. 这个模式不在GoF的23中设计模式内, 但是绝对是一个很常用, 很实用的模式 --- 空对象模式.

空对象模式(Null Object Pattern):
用一个空(什么都不做的)对象来代替NULL.

空对象模式是一个很简单的设计模式, 也可以看成是一种编码习惯. 它小但是作用大:

  • 使用空对象模式可以减少很多我们对于对象是否为空的判断. 例如本例中, 如果Checkstand的无参构造函数我们没有new一个空对象, 那么后续的对于Checkstand实例各种调用我们可能就需要判断其mActivityStrategy是否为空. 如果遗漏, 很有可能导致null pointer异常.
  • 另外对于一些可以链式调用的对象, 如果我们要每次都判断是否为空会很影响我们的链式调用.

空对象模式经常会用来作为策略模式算法族中的一个, 来提供空策略.

扩展阅读三

策略模式由于其优秀的对外扩展性和对内封装性, 在一些SDK或是优秀开源库中会经常用到. 还是以Glide为例, 其图片的磁盘缓存就使用了策略模式, 并提供了很多策略供用户选择:

优秀源码总是设计巧妙但又易懂不晦涩.

活动搞起了, 小光热干面欢迎大家常来光临啊, 喜欢您就收藏, 喜欢您就关注...

回馈顾客, 活动搞起 --- 策略模式相关推荐

  1. 一文搞懂策略模式(优化策略模式完全消除if else)

    注重版权,转载请注明原作者和原文链接 作者:码农BookSea 原文链接:https://blog.csdn.net/bookssea/article/details/117043820?spm=10 ...

  2. 20,000 字帮你搞定策略模式!

    点击上方"程序猿技术大咖",关注加群讨论 作者丨路易小七 来源丨www.cnblogs.com/lewis0077/p/5133812.html 在讲策略模式之前,我们先看一个日常 ...

  3. java商场满减活动_Java使用策略模式解决商场促销商品问题示例

    本文实例讲述了Java使用策略模式解决商场促销商品问题.分享给大家供大家参考,具体如下: 一 模式定义 策略模式:定义一系列的算法,将每一种算法封装起来并可以相互替换使用,策略模式让算法独立于使用它的 ...

  4. 策略模式(用策略模式实现我们淘宝,京东,美团等等简易满减活动)

    策略模式 源码地址:https://github.com/LiJiaHa0/pattern-strategy.git 策略模式是指定义了多个算法,称为算法家族,分别封装起来,让它们之间互相替换,此模式 ...

  5. 工厂模式+策略模式组合实现电商促销活动

    项目中大多数设计模式都是组合使用的,对于单个设计模式小伙伴们可以去菜鸟教程学习一下,下面使用 Java 实现的工厂模式+策略模式组合实现电商促销 首先,根据策略的不同,一些需要优惠计算,一些需要普通计 ...

  6. 1小时搞懂设计模式之策略模式

    1 什么是策略模式 简单一句话理解就是通过不同的方式来完成一件事.我们拿生活举例:年终将至又到了涨工资的时候了,领导会根据你今年工作表现来将员工分为三种: 工作不积极的坏员工 对于坏员工执行不涨薪策略 ...

  7. 从零开始单排学设计模式「策略模式」黑铁 II

    阅读本文大概需要 1.7 分钟. 本篇是设计模式系列的第三篇,虽然之前也写过相应的文章,但是因为种种原因后来断掉了,而且发现之前写的内容也很渣,不够系统.所以现在打算重写,加上距离现在也有一段时间了, ...

  8. 面向对象编程思想(2)--策略模式

    定义 策略模式 官方定义:定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换. 个人理解:选择执行多个规则中的某个规则. C#实现 需求1: 开发一个商场收银系统v1.0 三下五除二 ...

  9. 《大话》之 策略模式 Vs 状态模式

    一.简介: 策略模式: 背景:商店要打折销售,各种版本的销售方式,让小菜心烦意乱 内容:    定义算法家族,分别封装起来,让他们之间可以户型替换,此模式让算法的变化,不会影响到使用算法的用户. 图文 ...

最新文章

  1. 内存、性能问题分析的利器——valgraind
  2. oracle如何升序,oracle排序操作
  3. 配置MySQL数据库单机多实例
  4. IPv6扩展头部 (三) 路由头部 Routing Header for IPv6
  5. 电脑分屏软件_一招定鲜 | 电脑实现分屏解决了办公和娱乐
  6. 【数学建模】MATLAB从入门到精通:Logistic模型原理及应用案例(附MATLAB代码)
  7. C语言中的二级指针和二维数组问题
  8. Activity的启动模式详解
  9. python 字符串 find_Python 字符串 find() 方法
  10. 05.SQL Server大数据群集小试牛刀--HDFS查询
  11. Oracle期末考试总复习资料
  12. ora-00119和ora-00132解决方案
  13. 深度学习(01)——安装anaconda
  14. shell学习笔记二
  15. 三菱Q系列常用注意事项
  16. aforge java_java(一些java API)或C#(emgucv,dshownet,Aforge.NET)中的实时对象跟踪
  17. matlab恒压频比,基于matlab的三相异步电机恒压频比调速仿真.doc
  18. Tiny6410 SD卡启动裸机程序
  19. AP(接入点)模式、Router(无线路由)模式、Repeater(中继)模式、Bridge(桥接)模式、 Client(客户端)模式
  20. 什么是敏捷BI?和传统BI有什么不同?

热门文章

  1. angular 手动注入_手动引导Angular JS应用程序
  2. 智能指针 enable_shared_from_this 陷阱
  3. springboot中配置文件application.properties的配置详情,数据源配置
  4. vscode中vue-cli项目es-lint的配置
  5. 一套提取自 Ant Design 的优质图标
  6. Maven系列(一):Maven简介
  7. POJ 3037 SPFA
  8. APUE读书笔记-13守护进程(05)
  9. 程序员面试金典——1.8反转子串
  10. Matlab之三维曲面的绘制