【设计模式】阿里终面:你觉得这个例子是策略模式吗?

什么是策略模式?

策略模式,举几个贴近生活的例子:当我们出行的时候,不同的出行方式就是不同的策略,例如走路、开车、骑自行车、坐飞机、坐邮轮等等,每一种出行方式都代表着不同的费用和时间;当我们去商场超市的时候,可能正好打折,也可能正好满减,又或者积分返利等等**,这些都是策略!**

先来看看策略模式的定义:策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

策略模式的精髓就在于将经常变化的一点提取出来,单独变成一类,并且各个类别可以相互替换和组合,类图关系如下:

img

结合策略模式的类图,可知策略模式主要由三个部分构成:抽象的策略类(所有具体的策略都需要继承它)、具体的策略类(实现了各种不同的策略方法)、上下文类或者说必备参数类(其中主要维护着一个具体策略类的引用,以及策略所必备的上下参数)。

策略模式通过context上下文类来自由的选择所要采取的方法:

public class AbstractContext {AbstractStrategy strategy;//初始化时传入具体的策略对象public AbstractContext(AbstractStrategy strategy) {this.strategy = strategy;}//上下文接口,调用策略的具体方法public void ContextInterface() {strategy.ItsInterface();}
}

而对应的方法都是继承与同一个抽象的策略类

public abstract class AbstractStrategy {//留待子类自己实现public void ItsInterface(){}
}

具体的策略类实现在子类中进行重载,如下:

public class FakeStrategy extends AbstractStrategy{@Override//子类实现的具体方法public void ItsInterface() {System.out.println("I'm using this method");}
}

具体实现

策略模式所要解决的问题主要是在多种算法极其相似的情况下,让对象根据上下文(context)进行具体实现的选择。例如正如我们开篇所提到的那样,选择出门的方式:骑车、开车、走路等等,甚至骑车一段时间、走路一段时间、坐飞机一段时间。

我觉得《大话设计模式》举的例子十分贴切:某商场搞促销活动,有打折活动、满减活动(两个可同时进行),并且打折的力度和满减的程度可能在今后需要进行修正,那么应当如何设计整个系统呢?

策略模式实现

假设现在商场有三种结算方式:正常结算、打折结算、返利结算。根据策略模式的思想,我们可以设计一个这样的系统:

img

  • 上下文类

先创建一个抽象的上下文类,根据传入策略类来获得具体的优惠策略,调用getPrice()来获取最终需要支付的结果。

public class CashContext {private CashAbstract CashAbstract;public CashContext(CashAbstract CashAbstract) {this.CashAbstract = CashAbstract;}public double getResult(double money) {return CashAbstract.acceptCash(money);}
}
  • 抽象策略类

抽象策略类在这里指的是根据商场活动以及顾客的消费额来计算真正应该支付的金额:

public abstract class CashAbstract {public abstract double acceptCash(double money);
}
  • 三种具体的策略子类

商场活动一共有三种:正常收费(无活动)、打折收费、返利收费,这里只给出返利收费的实现:

public class CashReturn extends CashAbstract {//返利收费,初始化时必须输入返利条件以及返利金额private double moneyCondition = 0.0;private double moneyReturn = 0.0d;public CashReturn(double moneyCondition, double moneyReturn) {this.moneyCondition = moneyCondition;this.moneyReturn = moneyReturn;}@Overridepublic double acceptCash(double money) {double result = money;if (money >= moneyCondition) {result = money - Math.floor(money / moneyCondition) * moneyReturn;}return result;}
}
  • 测试一下我们的设计的收费系统
public class App {public static void main(String[] args) {CashContext cashContext = null;Scanner scanner = new Scanner(System.in);System.out.print("请输入活动内容:1是正常收费,2是返利收费,3是打折活动");int in = scanner.nextInt();String type = "";switch (in) {case 1:cashContext = new CashContext(new CashNormal());type += "正常收费";break;case 2:cashContext = new CashContext(new CashReturn(300, 100));type += "满300返100";break;case 3:cashContext = new CashContext(new CashRebate(0.8));type += "打8折";break;default:System.out.println("请输入1/2/3");break;}double totalPrices = 0;System.out.print("请输入单价:");double price = scanner.nextDouble();System.out.print("请输入数量:");double num = scanner.nextDouble();totalPrices = cashContext.getPrice(price * num);System.out.println("单价:" + price + ",数量:" + num + ",类型:" + type + ",合计:" + totalPrices);scanner.close();}
}

正常活动模式:

img

返利活动模式:

img

打折活动模式:

img

可见,我们设计的收费系统是没问题的。

策略模式+简单工厂

虽然,上述策略模式的实现能够正常运行,且满足当前的需求。但是,代码无错便是优吗?当然不是!

仔细想想,按照上文代码的实现思路,如果新增一个活动类别,岂不是还需要在switch-case种加一个分支?

img

并且,客户端代码里“耦合”了多个对象:cashContext与cashNormal、cashReturn、CashRebate。客户端耦合的对象越多,之后的修改和拓展就会越来越困难。

在之前介绍三种工厂模式的时候我们提到,当遇到这种switch-case语句的时候,往往都可以使用简单工厂模式来解决,又或者通过反射来简化代码。

大伙不妨试一试?

总结

先说说策略的优缺点:

策略模式的优点就在于可以灵活的选择需要使用的算法,减少ifelse语句

缺点就是,如果具体的策略类较多的话,各个策略类之间不具有复用性

具体的应用场景呢?

需要进行算法切换的场景,且各个算法之间只有实现上的差异,其余参数可以抽离出来共用。

参考链接

《大话设计模式》

《Head First 设计模式》

https://www.cnblogs.com/adamjwh/p/11011095.html

项目地址

https://github.com/white0dew/Design-pattern/tree/master

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/652021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

make: *** No rule to make target ‘clean‘. Stop.

项目场景: 在Ubuntu下编写makefile文件编译的时候,出现make: *** No rule to make target ‘clean’. Stop. 问题描述 make: *** No rule to make target ‘clean’. Stop. 解决方案: 原本我makefile文件的名字是MakeFile , 把它改为makefile以后完美运…

腾讯云OpenCloudOS安装ES(elasticsearch7.17.16)

腾讯云OpenCloudOS安装ES(elasticsearch7.17.16) 下载ES 先从官网下载es的Linux解压包官网地址 https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-17-16 下载完成后,将其放置在自己想要放到的路径下 配置ES 解压文件 …

第五季特别篇:一夜杯、游戏之宴 2017.04.26

第五季特别篇:一夜杯、游戏之宴 2017.04.26 OVA 第1话:一夜酒杯 / 一夜杯OVA 第2话:游戏之宴 / 遊戯の宴 OVA 第1话:一夜酒杯 / 一夜杯 遭到独角妖袭击的妖怪夫妇日土和初菜被夏目所救,这对妖怪夫妇制作的酒杯&#xf…

R数据分析:非劣效性研究设计的统计处理方法,原理和实例

在我们经常接触的统计模式中,我们是在寻求推翻原假设,证明差异,这种统计模型在传统的临床试验中,在各种统计推断中已经成为默认了。在传统的临床试验中通常会将一种新的治疗方法与标准治疗或安慰剂进行比较,从而证明这…

###C语言程序设计-----C语言学习(5)#

前言:感谢您的关注哦,我会持续更新编程相关知识,愿您在这里有所收获。如果有任何问题,欢迎沟通交流!期待与您在学习编程的道路上共同进步! 一. 主干知识的学习 1.switch语句 switch语句可以处理多分支选…

Linux详细笔记大全

第0章 Linux基础入门 什么是计算机 计算机的组成: 控制器,是整个计算机的中枢神经,根据程序要求进行控制,协调计算机各部分工作及内存与外设的访问等。 运算器,功能是对数据进行各种算术运算和逻辑运算。 存储器,功能是存储程序、数据和各种信号、命令等信息。 输入设备…

第二模块 函数模块

第二模块 函数&模块 day09 文件操作相关1. 文件操作1.1 读文件1.2 写文件1.3 文件打开模式1.4 常见功能1.5 上下文管理练习题 2.csv格式文件3.ini格式文件4.XML格式文件4.1 读取文件和内容4.2 读取节点数据4.3 修改和删除节点4.4 构建文档 5.Excel格式文件5.1 读Excel5.1 写…

微信小程序之页面导航、生命周期和WXS脚本

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…

Python 使用重构重命名一键更改变量名的方法

一个变量有多处引用的情况下,需要重命名,可以使用重构重命名进行一键更改。 方法是:选择变量名–>右键–>Refactor–>Rename(也可以使用快捷:选择变量后按下ShiftF6),然后直接输入新的变量名即可…

基于Matlab/Simulink直驱式风电储能制氢仿真模型

接着还是以直驱式风电为DG中的研究对象,上篇博客考虑的风电并网惯性的问题,这边博客主要讨论功率消纳的问题。 考虑到风速是随机变化的,导致风电输出功率的波动性和间歇性问题突出;随着其应用规模的不断扩大以及风电在电网中渗透率…

[echarts] 图表工具栏 toolbox

option{// 工具栏配置toolbox:{id:1, // 组件IDshow:true, // 是否显示工具栏orient:horizontal, // 工具栏 icon 的布局朝向itemSize:15, // 工具栏 icon 的大小itemGap:10, // 工具栏…

DjangoURL调度器(二)

一、默认值与额外参数 1.1、默认值 1.1.1、urls.py from django.urls import pathfrom . import viewsurlpatterns [# http://127.0.0.1:8000/polls/blog/ 等同于 # http://127.0.0.1:8000/polls/blog/1/path(blog/, views.page),# http://127.0.0.1:8000/polls/blo…

springboot项目开发,使用thymeleaf前端框架的简单案例

springboot项目开发,使用thymeleaf前端框架的简单案例!我们看一下,如何在springboot项目里面简单的构建一个thymeleaf的前端页面。来完成动态数据的渲染效果。 第一步,我们在上一小节,已经提前预下载了对应的组件了。 如图&#x…

vue之pinia存储和读取数据

我们已经搭建好了pinia的环境,现在我们使用pinia来存储和读取数据。Pinia是Vue的状态管理库,允许在Vue组件之间共享状态。 vue的pinia环境搭建 创建一个store文件,包含count.ts和lovetalk.ts,存储数据 import { defineStore }…

签到业务流程

1.技术选型 Redis主写入查询,Mysql辅助查询,传统签到多数都是直接采用mysql为存储DB,在大数据的情况下数据库的压力较大.查询速率也会随着数据量增大而增加.所以在需求定稿以后查阅了很多签到实现方式,发现用redis做签到会有很大的优势.本功能主要用到r…

python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-自定义帖子管理实现

锋哥原创的SpringbootLayui python222网站实战: python222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火…

Django学习之小试牛刀

六、Django学习之小试牛刀 其他关于Python Web开发笔记:(如果遇到问题可以一起交流~) 一、Flask学习之HTML-CSDN博客 二、Flask学习之CSS-CSDN博客 【接上篇】二、Flask学习之CSS(下篇)-CSDN博客 三、Flask学习之B…

面试题:Spring在多线程环境下如何确保事务一致性

文章目录 问题在现如何解决异步执行多线程环境下如何确保事务一致性事务回顾事务实现方式回顾编程式事务那么编程式事务是什么样子呢? 利用编程式事务解决问题问题分析完了,那么如何解决问题呢?总结 问题在现 我先把问题抛出来,大…

LandrayOA内存调优 / JAVA内存调优 / Tomcat web.xml 超时时间调优实战

目录 一、背景说明 二、LandrayOA / Tomcat 内存调优 2.1 \win64\tomcat\conf\web.xml 文件调优 2.2 \win64\tomcat\bin\catalina64.bat 文件调优 一、背景说明 随着系统的使用时间越来越长,数据量越多,发现系统的有些功能越来越慢&…

基于InceptionV2/InceptionV3/Xception不同参数量级模型开发构建中草药图像识别分析系统,实验量化对比不同模型性能

最近正好项目中在做一些识别相关的内容,我也陆陆续续写了一些实验性质的博文用于对自己使用过的模型进行真实数据的评测对比分析,感兴趣的话可以自行移步阅读即可: 《移动端轻量级模型开发谁更胜一筹,efficientnet、mobilenetv2、…