定义

策略模式
官方定义:定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。
个人理解:选择执行多个规则中的某个规则。

C#实现

需求1: 开发一个商场收银系统v1.0

三下五除二搞定

代码实现:

var price = Convert.ToDouble(txtPrice.Text);//单价
var number = Convert.ToDouble(txtNumber.Text);//数量
var lastTotal = Convert.ToDouble(labTotal.Text);//已购买金额var money = price * number;//本次计算金额
labTotal.Text = (lastTotal + money).ToString();
txtContent.Text += string.Format("单价:{0},数量:{1},金额:{2}", price, number, money + "\r\n");

系统简单、方便、实用、性能好。...几个月过去,马上要国庆长假,老板为了促销决定全场8.8折。

需求2: 加入打折功能
因为项目工期紧,三下五除二又搞定

var price = Convert.ToDouble(txtPrice.Text);//单价
var number = Convert.ToDouble(txtNumber.Text);//数量
var lastTotal = Convert.ToDouble(labTotal.Text);//已购买金额
var discount = 0.88;//折扣(新增代码)var money = price * number * discount;//本次计算金额
labTotal.Text = (lastTotal + money).ToString();
txtContent.Text += string.Format("单价:{0},数量:{1},折扣:{2},实际金额:{2}", price, number, discount, money + "\r\n");

很是自豪,我开发效率就是这么高。老板也甚是高兴。
...转眼假期就要过去了,打折的活动也要取消了。但是,由于这次的促销效果收益还不错。老板决定继续打折活动,折扣率要成为9.8折,且只是部分商品。不打折的商品则实行满300返40,满600返100。
不对劲啊,又的改代码。到了明年是不是又要8.8?老板的心思猜不透,但程序可以写得更灵活。所以我们要好好构思下。让系统可以选择优惠策略。

需求3: 修改打折,并加入返现功能

代码实现如下

var price = Convert.ToDouble(txtPrice.Text);//单价
var number = Convert.ToDouble(txtNumber.Text);//数量
var lastTotal = Convert.ToDouble(labTotal.Text);//已购买金额
var money = price * number;//本次计算金额
switch (cmBstrategy.Text)//下拉框
{case "8.8折":money *= 0.88;break;case "9.8折":money *= 0.98;break;case "满300返40":if (money >= 300){money -= 40;}break;case "满600返100":if (money >= 600){money -= 100;}break;
}labTotal.Text = (lastTotal + money).ToString();
txtContent.Text += string.Format("单价:{0},数量:{1},促销:{2},实际金额:{3}", price, number, cmBstrategy.Text, money + "\r\n");

现在我们的收银员可以灵活切换优惠活动,且保留的原有的优惠策略。不过我们从代码层面考虑的话,还有多处不足。

  • switch条件分支语句难以阅读和维护。
  • 如果我们需要修改新增优惠策略的话,需在界面代码里面修改。

根据面向对象的思想,应该封装变化。于是,我们的策略模式可以登场了。

代码重构 使用策略模式实现以上需求

var price = Convert.ToDouble(txtPrice.Text);//单价
var number = Convert.ToDouble(txtNumber.Text);//数量
var lastTotal = Convert.ToDouble(labTotal.Text);//已购买金额      var context = new Context(cmBstrategy.Text);//新增代码
var money = context.Calculation(price, number);//新增代码labTotal.Text = (lastTotal + money).ToString();
txtContent.Text += string.Format("单价:{0},数量:{1},促销:{2},实际金额:{3}", price, number, cmBstrategy.Text, money + "\r\n");

我们发现中间那段条件分支不见了,多了一个Context类。

public class Context
{//策略抽象类private AmountCalculation amountCalculation;public Context(string type){switch (type){case "8.8折":amountCalculation = new Rebate(0.88);break;case "9.8折":amountCalculation = new Rebate(0.98);break;case "满300返40":amountCalculation = new Cashback(300, 40);break;case "满600返100":amountCalculation = new Cashback(600, 100);break;}}//计算金额public double Calculation(double price, double number){return amountCalculation.Calculation(price, number);}
}

里面有类Rebate折扣计算、Cashback返现计算。

//折扣计算
public class Rebate : AmountCalculation
{private double discountRate;public Rebate(double discountRate){this.discountRate = discountRate;}public override double Calculation(double price, double number){return price * number * discountRate;}
}
// 返现
public class Cashback : AmountCalculation
{//满多少private double exceed;//返多少private double retreat;public Cashback(double exceed, double retreat){this.exceed = exceed;this.retreat = retreat;}public override double Calculation(double price, double number){var momoney = price * number;if (momoney >= exceed){return momoney - retreat;}return momoney;}
}

看到这里,是不是明白了策略模式呢?
如果现在老板再需要我们价格折扣或是返现的活动,相比之前需要在长段的界面逻辑代码里面修改,现在要方便得多了。
第一、先在界面添加一个活动如加一个7.8折,然后界面代码就不用动了。
第二、在Context类里面加一个7.8折

switch (type)
{//新增case "7.8折":amountCalculation = new Rebate(0.78);break;

JS实现

上面用C#实现了策略模式,接下来我们尝试使用js来实现。还是借用用上面的商场活动业务。
js不同于传统的面向对象,无类、不需要实现抽象类。

//策略计算
var strategies = {//返现  exceed:满多少  retreat:返多少  momoney:应付金额cashBack: function (exceed, retreat, momoney) {if (momoney >= exceed) {return (momoney - retreat).toFixed(2);}return momoney;//返现后实付金额},//打折 discountRate:折扣率  momoney:应付金额rebate: function (discountRate, momoney) {return (discountRate * momoney).toFixed(2);//折扣后实付金额}
}
//上下文
var context = {"7.8折": function (price, number) {var momoney = price * number;return strategies.rebate(0.78, momoney);},"9.8折": function (price, number) {var momoney = price * number;return strategies.rebate(0.98, momoney);},"满300返40": function (price, number) {var momoney = price * number;return strategies.cashBack(300, 40, momoney);},"满600返100": function (price, number) {var momoney = price * number;return strategies.cashBack(600, 100, momoney);}
}
//计算结果
var calculateBonus = function (level, price, number) {return context[level](price, number);
};
//调用
console.log(calculateBonus('7.8折', 12, 3));//计算
console.log(calculateBonus('满600返100', 12, 3));//计算
console.log(calculateBonus('满300返40', 2, 23));//计算
console.log(calculateBonus('9.8折', 2, 33));//计算

结果如下:

相对于面向对象语言的实现要更加的清晰明了。
那么js可以模拟面向对象的实现吗?答案是肯定的。
首先定义返现实现类:

//返现  exceed:满多少  retreat:返多少
var CashBack = function (exceed, retreat) {this.exceed = exceed;this.retreat = retreat;
};
//计算方法
CashBack.prototype.calculate = function (price, number) {var momoney = price * number;if (momoney >= this.exceed) {return (momoney - this.retreat).toFixed(2);}return momoney;//返现后实付金额
}

打折类

//打折 discountRate:折扣率  momoney:应付金额
var Rebate = function (discountRate) {this.discountRate = discountRate;
};
//计算方法
Rebate.prototype.calculate = function (price, number) {return (price * number * this.discountRate).toFixed(2);//折扣后实付金额
}

策略上下文

//上下文
var Context = function (type) {this.type = type;
}
Context.prototype.calculation = function (price, number) {var AmountCalculation;switch (this.type) {case "7.8折":AmountCalculation = new Rebate(0.78);break;case "9.8折":AmountCalculation = new Rebate(0.98);break;case "满300返40":AmountCalculation = new CashBack(300, 40);break;case "满600返100":AmountCalculation = new CashBack(600, 100);break;}return AmountCalculation.calculate(price, number);
}

调用如下:

//调用
var context = new Context("7.8折");
console.log(context.calculation(12, 3));
var context = new Context("9.8折");
console.log(context.calculation(12, 3));//计算
var context = new Context("满300返40");
console.log(context.calculation(300, 2));//计算
var context = new Context("满600返100");
console.log(context.calculation(300, 3));//计算


虽然对于js语言特性直接实现策略模式来说,面向对象的代码量比较多。可是对于我们后端人员new一个对象的使用方式应该更习惯。

策略模式场景

  • 排序算法的选择冒泡排序、选择排序、快速排序、插入排序
  • 压缩算法的选择zip、rar、rar5...
  • 旅游交通工具的选择飞机、火车、汽车...

总结
策略模式通过Context上下文对具体策略进行封装,供高层直接调用而不用关系策略的具体实现。然后Context本身通过不同情况实例不同的抽象实现类(具体策略类),来执行具体策略。从而实现了具体策略的自由切换,易于新策略的扩展。
本文已同步至索引目录:《设计模式学习》
本文demo:https://github.com/zhaopeiym/BlogDemoCode

面向对象编程思想(2)--策略模式相关推荐

  1. 基于STM32F103移植华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机

    华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机 因为在做华为LiteOS任务挂起和恢复需要使用到按键去触发任务挂起和恢复动作,因为我就萌发出使用状态机这种架构做一个按键检测触发.回想已 ...

  2. JavaScript 面向对象编程思想简介

    JavaScript 面向对象编程 JavaScript 执行过程 JavaScript 面向对象编程 面向对象介绍 什么是对象 什么是面向对象 程序中面向对象的基本体现 创建对象 简单方式 简单方式 ...

  3. JavaScript 面向对象编程思想

    JavaScript 面向对象编程思想 什么是面向对象 面向对象不是新的东西,它只是过程式代码的一种高度封装,目的在于提高代码的开发效率和可维护性. 面向对象编程 -- Object Oriented ...

  4. CoreJava学习第五课 --- 进入第二阶段:面向对象编程思想

    面向对象编程思想 1.面向过程 ​ 从计算机执行角度出发 ,代码执行过程核心为从程序的运行过程出发,构建编程思路,例: 哥德巴赫猜想 // 面向过程1 用户输入一个数n2 验证数字的正确性2.1 正确 ...

  5. 面向对象编程思想概览(一)类和对象

    一.简介 生活中有许多技巧值得我们在程序设计中模仿和借鉴.采用类的思想可以方便地把具有相同属性和方法归为一类,从而简化编程.本讲利用生活的常见示例,浅显通俗的语言,生动地介绍了面向对象编程中类与对象的 ...

  6. python完全支持面向对象编程思想_面向对象的编程思想和Python的类,访问和属性,继承...

    本文将从访问限制,属性,继承,方法重写这几个方面继续介绍面向对象的编程思想和Python类的继承. 复制代码 一.访问权限: Python中在类的内部定义属性和方法,在类的外部是可以直接调用或进行访问 ...

  7. 面向对象编程思想概览(三)继承

    一.简介 本讲以大家耳熟能详的<西游记>中的唐僧师徒四人为例,介绍了类的继承的概念和实现方法,总结了继承的特性和优点,帮助同学们理解面向对象编程中继承的用法,进而掌握面向对象程序设计的基本 ...

  8. 面向对象编程思想 以及类与对象

    一.面向对象编程思想 众所周知,我们常见的编程思想有面向过程和面向对象两种,像我们最基础的c语言,就是一种以过程为中心的编程思想,不关注具体的事件和对象而是针对于解决问题的思路和目标,这种编程思想由于 ...

  9. 面向对象编程思想及入门知识

    这几天在调程序,所以想写写自己对"面向对象编程"的一些理解,希望对打算入门计算机编程的同志们有所帮助.之前,好几个师弟问过我,C++与C有什么区别,学习面向对象语言需要掌握哪些基础 ...

最新文章

  1. 【Live555】live555源码详解(四):Medium媒体基础类
  2. ASP.NET MVC – 样式和布局简介
  3. nc 传输文件和目录
  4. 得到app文稿导出_再见了扫描仪!微信打开这个功能,一键将纸质文稿扫描成电子档...
  5. matlab armax 无法识别,求教:Java调用系统辨识工具箱内的armax函数出错
  6. 摆脱困境:将属性值注入配置Bean
  7. 在Nature、Science正刊等国际知名杂志发表论文,可直接申报正高级职称!
  8. Python学习入门9:如何高效学Python?
  9. Head first 第一章
  10. [转]使用.NET实现断点续传
  11. 架构师资源汇总 从入门到精通 将近20年的工作经验毫无保留分享
  12. 【超详细】| 使用Vmware 安装win7虚拟机
  13. 汉王数据导入java环境,汉王数据管理系统导入数据怎样进行数据更新,只导出一天的考勤数据?...
  14. 美国之行---领略真正的美国文化--牛排
  15. 已解决json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
  16. 全球及中国冶金工业市场产量分析及投资战略决策报告2021版
  17. 二义性文法的理解和消除方法
  18. 2022-2028年全球及中国汽车保险丝行业投资前景分析
  19. 0.4-如何使用DAP LINK 下载Hex程序?
  20. 赋值具有的非单一 rhs 维度多于非单一下标数错误的分析和解决方法

热门文章

  1. java.util.concurrent.CyclicBarrier;
  2. eclipse 怎么关闭 show children
  3. if __name__ == __main__
  4. oracle em 按钮乱码解决办法
  5. Citrix Xendesktop中VDA注册DDC的流程
  6. Android recipe 在代码中写布局
  7. 打印容器_喷墨打印MnO?制备微型超级电容器
  8. 5G NPN 行业专网 — 部署模式
  9. etcd — 架构原理
  10. echo -n 和echo -e 参数意义