首页 > 编程语言 >JavaScript 设计模式之策略模式

JavaScript 设计模式之策略模式

时间:2022-10-24 17:33:41浏览次数:50  
标签:status getPrice return JavaScript 模式 origialPrice originalPrice 设计模式

JavaScript 设计模式之策略模式_代码设计

什么是设计模式?为什么需要学习设计模式?

学习设计模式的目的是:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

经典的设计模式有 23 种,但并不是每一种设计模式都被频繁使用。在这里,介绍最常用和最实用的几种设计模式,本文先来介绍策略模式(Strategy Pattern)。


策略模式是一种行为设计模式,定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。

假如正在开发一个在线商城的项目,每个产品都有原价,称之为 ​​originalPrice​​。但实际上并非所有产品都以原价出售,可能会推出允许以折扣价出售商品的促销活动。

商家可以在后台为产品设置不同的状态,然后实际售价将根据产品状态和原价动态调整。

具体规则如下:

  • 部分产品已预售:为鼓励客户预订,将在原价基础上享受​​20%​​ 的折扣。
  • 部分产品处于正常促销阶段:如果原价低于或等于​​100​​,则以​​10%​​的折扣出售;如果原价高于​​100​​,则减​​10​​ 元。
  • 有些产品没有任何促销活动:它们属于​​default​​ 状态,并以原价出售。

这时需要写一个获取商品价格的函数 ​​getPrice​​ ,应该怎么写呢?

function getPrice(originalPrice, status) {
// ...
// 返回价格;
}

事实上,面对这样的问题,如果不考虑任何设计模式,最直观的写法可能 ​​if-else​​ 多次条件判断语句来计算价格。

有三种状态,可以快速编写如下代码:

function getPrice(originalPrice, status) {
if (status === "pre-sale") {
return originalPrice * 0.8;
}

if (status === "promotion") {
if (origialPrice <= 100) {
return origialPrice * 0.9;
} else {
return originalPrice - 20;
}
}

if (status === "default") {
return originalPrice;
}
}

有三个条件,上面的代码写了三个 ​​if​​ 语句,这是非常直观的代码,但是这段代码组织上不好。

首先,它违反了单一职责原则(Single responsibility principle,规定每个类或者函数都应该有一个单一的功能,并且该功能应该由这个类或者函数完全封装起来)。函数 ​​getPrice​​ 做了太多的事情,这个函数不易阅读,也容易出现 ​​bug​​ 。如果一个条件出现 ​​bug​​ ,整个函数就会崩溃。同时,这样的代码也不容易调试。

并且这段代码很难应对变化的需求,这时就需要考虑设计模式,其往往会在业务逻辑发生变化时展现出它的魅力。

假设业务扩大了,现在还有另一个折扣促销:黑色星期五。折扣规则如下:

  • 价格低于或等于 100 元的产品以 20% 的折扣出售。
  • 价格高于 100 元但低于 200 元的产品将减少 20 元。
  • 价格高于或等于 200 元的产品将减少 20 元。

这个时候该怎么扩展 ​​getPrice​​ 函数呢?

看起来必须在 ​​getPrice​​ 函数中添加一个条件语句:

function getPrice(originalPrice, status) {
if (status === "pre-sale") {
return originalPrice * 0.8;
}

if (status === "promotion") {
if (origialPrice <= 100) {
return origialPrice * 0.9;
} else {
return originalPrice - 20;
}
}
// 黑色星期五规则
if (status === "black-friday") {
if (origialPrice >= 100 && originalPrice < 200) {
return origialPrice - 20;
} else if (originalPrice >= 200) {
return originalPrice - 50;
} else {
return originalPrice * 0.8;
}
}

if (status === "default") {
return originalPrice;
}
}

每当增加或减少折扣时,都需要更改函数。这种做法违反了开闭原则(对扩展开放,对修改关闭)。修改已有的功能很容易出现新的错误,而且还会使得 ​​getPrice​​ 越来越臃肿。

那么如何优化这段代码呢?

首先,可以拆分这个函数 ​​getPrice​​ 以减少臃肿。

/**
* 预售商品价格规则
* @param {*} origialPrice
* @returns
*/
function preSalePrice(origialPrice) {
return originalPrice * 0.8;
}
/**
* 促销商品价格规则
* @param {*} origialPrice
* @returns
*/
function promotionPrice(origialPrice) {
if (origialPrice <= 100) {
return origialPrice * 0.9;
} else {
return originalPrice - 20;
}
}
/**
* 黑色星期五促销规则
* @param {*} origialPrice
* @returns
*/
function blackFridayPrice(origialPrice) {
if (origialPrice >= 100 && originalPrice < 200) {
return origialPrice - 20;
} else if (originalPrice >= 200) {
return originalPrice - 50;
} else {
return originalPrice * 0.8;
}
}
/**
* 默认商品价格
* @param {*} origialPrice
* @returns
*/
function defaultPrice(origialPrice) {
return origialPrice;
}

function getPrice(originalPrice, status) {
if (status === "pre-sale") {
return preSalePrice(originalPrice);
}

if (status === "promotion") {
return promotionPrice(originalPrice);
}

if (status === "black-friday") {
return blackFridayPrice(originalPrice);
}

if (status === "default") {
return defaultPrice(originalPrice);
}
}

经过这次修改,虽然代码行数增加了,但是可读性有了明显的提升。​​getPrice​​ 函数显然没有那么臃肿,写单元测试也比较方便。

但是上面的改动并没有解决根本的问题:代码还是充满了 ​​if-else​​ ,而且当增加或者减少折扣规则的时候,仍然需要修改 ​​getPrice​​。

其实使用这些 ​​if-else​​ 的目的就是为了对应状态和折扣策略。

JavaScript 设计模式之策略模式_代码设计_02

从图中可以发现,这个逻辑本质上是一种映射关系:产品状态与折扣策略的映射关系。

可以使用映射而不是冗长的 ​​if-else​​ 来存储映射,按照这个思路可以构造一个价格策略的映射关系(策略名称与其处理函数之间的映射),如下:

const priceStrategies = {
"pre-sale": preSalePrice,
promotion: promotionPrice,
"black-friday": blackFridayPrice,
default: defaultPrice,
};

将状态与折扣策略结合起来,价格函数就可以优化成如下:

function getPrice(originalPrice, status) {
return priceStrategies[status](originalPrice);
}

这时候如果需要加减折扣策略,不需要修改函数,只需要修改价格策略映射关系 ​​priceStrategies​

之前的代码逻辑如下:

JavaScript 设计模式之策略模式_策略模式_03

优化后的代码逻辑如下:

JavaScript 设计模式之策略模式_代码设计_04

以上的优化策略就是使用了设计模式之策略模式,在实际的项目开发过程中还是比较实用。

在什么情况下可以考虑使用策略模式呢?如果函数具有以下特征:

  • 判断条件很多
  • 各个判断条件下的代码相互独立

然后可以将每个判断条件下的代码封装成一个独立的函数,然后建立判断条件和具体策略的映射关系。

标签:status,getPrice,return,JavaScript,模式,origialPrice,originalPrice,设计模式
From: https://blog.51cto.com/devpoint/5788804

相关文章

  • 浅析 Dapr 里的云计算设计模式
    Dapr实际上是把分布式系统与微服务架构实践的挑战以及k8s这三个主题的全方位的设计组合,特别是Kubernetes设计模式一书作者BilginIbryam提出的Multi......
  • JavaScript对象-Date、Math
    JavaScript对象-Date<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Date对象</title><script>/*Date:......
  • 616Javascript_语法_练习_99乘法表 and
    练习9*9乘法表<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>99乘法表</title><style>td{border:1pxs......
  • JavaScript_对象-Function、Array
    JavaScript_对象-Function<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Function对象</title><script>/*......
  • 614 _Javascript_语法_特殊语法 and 615 _Javascript_语法_流程控制语句
    流程控制语句:         1.if...else...         2.switch:            在java中,switch语句可以接受的数据类型:byteintshorc......
  • 单例模式
    单例模式 饿汉式由于对象在类里面才能被创建,而且是静态的,所以,被创建的对象始终都是一个,由于在类装载时就被完成了实例化,所以没有线程安全问题,如果没有使用这个实例,会造......
  • 观察者模式
    观察者模式观察者模式(ObserverDesignPattern):在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会得到通知并自动更新。观察者模式通用代码/......
  • 直播电商平台开发,设计模式单例模式
    直播电商平台开发,设计模式单例模式1.说明单例即只有一个实例,比如说配置、日志、连接池等,可以避免多个实例带来的多余的资源开销,并且在多线程环境下保证数据安全 2.类......
  • JavaScript将成Silverlight的最大对手
    ​​​​在悉尼举办的微软Tech-Ed技术会议上,与会专家就微软的Silverlight的竞争对手究竟是Flash还是JavaScript展开了激烈辩论.在Google正式发布基于快速JavaScript技术......
  • 612Javascript_语法_逻辑运算符 and 613 Javascript_语法_三元运算符
    5.逻辑运算符            &&||!            *其他类型转boolean:                  1.number:0或NaN为假,其他为真......