前端也要学系列:设计模式之策略模式(代码片段)

depsi depsi     2022-11-16     412

关键词:

做前端开发已经好几年了,对设计模式一直没有深入学习总结过。随着架构相关的工作越来越多,越来越能感觉到设计模式成为了我前进道路上的一个阻碍。所以从今天开始深入学习和总结经典的设计模式以及面向对象的几大原则。

今天第一天,首先来讲策略模式。

什么是策略模式?

GoF四兄弟的经典《设计模式》中,对策略模式的定义如下:

定义一系列的算法,把它们一个个封装起来,并且使它们可互相替换。

上边这句话,从字面来看很简单。但是如何在开发过程中去应用,仅凭一个定义依然是一头雾水。以笔者曾经做过的商户进销存系统为例:

某超市准备举行促销活动,市场人员经过调查分析制定了一些促销策略:

  1. 购物满100减10
  2. 购物满200减30
  3. 购物满300减50
  4. 。。。

收银软件的界面是这样的(简单示意):

技术分享图片

我们应该如何计算实际消费金额?

最初的实现是这样的:

//方便起见,我们把各个促销策略定义为枚举值:0,1,2...
var getActualTotal = function(onSaleType,originTotal)
    if(onSaleType===0)
        return originTotal-Math.floor(originTotal/100)*10
    
    if(onSaleType===1)
        return originTotal-Math.floor(originTotal/200)*30
    
    if(onSaleType===0)
        return originTotal-Math.floor(originTotal/300)*50
    


getActualTotal(1,2680); //2208

上面这段代码很简单,而且缺点也很明显。随着我的满减策略逐渐增多,getActualTotal函数会越变越大,而且充满了if判断,稍一疏忽就容易弄错。

OK,有人说我很懒,虽然这样不够优雅但并不影响我的使用,毕竟满减策略再多也多不到哪去。
我只能说,需求永远不是程序员定的。。这时,市场人员说我们新版程序添加了会员功能,我们需要支持以下的促销策略:

会员促销策略:

  1. 会员充300返60,且首单打9折
  2. 会员充500返100,且首单打8折
  3. 会员充1000返300,且首单打7折
  4. ...

这个时候,如果你还在原先的getActualTotal函数中继续添加if判断,我想如果你的领导review你这段代码,可能会怀疑自己当初怎么把你招进来。。

OK,我们终于下定决心要重构促销策略的代码,我们可以这么做:

var vipPolicy_0=function(originTotal)
    return originTotal-Math.floor(originTotal/100)*10

var vipPolicy_1=function(originTotal)
    return originTotal-Math.floor(originTotal/200)*30

...
//会员充1000返300
var vipPolicy_10=function(account,originTotal)
    if(account===0)
        account+=1300;
        return originTotal*0.9
    else
        account+=1300;
        return originTotal;
    
    return originTotal-Math.floor(originTotal/200)*30

...
var vipPolicy_n=function()
    ...


var getActualTotal=function(onSaleType,originTotal,account)
    switch(onSaleType)
        case 0:
            return vipPolicy_0(originTotal);
        case 1:
            return vipPolicy_0(originTotal);
        ...
        case n:
            return ...
        default:
            return originTotal;
    

好了,现在我们每种策略都有自己独立的空间了,看起来井井有条。但是还有两个问题没有解决:

  1. 随着促销策略的增加,getActualTotal的代码量依然会越来越大
  2. 系统缺乏弹性,如果需要增加一种策略,那么除了添加一个策略函数,还需要修改switch...case..语句

让我们再来回顾一下策略模式的定义:

定义一系列的算法,把它们一个个封装起来,并且使它们可互相替换

在我们的例子中,每种促销策略的实现方式是不一样的,但我们最终的目的都是为了求得实际金额。策略模式可以把我们对促销策略的算法一个个封装起来,并且使它们可互相替换而不影响我们对实际金额的求值,这正好是我们所需要的。

下面我们用策略模式来重构上面的代码:

var policies=
    "Type_0":function(originTotal)
        return originTotal-Math.floor(originTotal/100)*10 
    ,
    "Type_1":function(originTotal)
        return originTotal-Math.floor(originTotal/200)*30 
    ,
    ...
    "Type_n":function(originTotal)
        ... 
    


var getActualTotal=function(onSaleType,originTotal,account)
    return policies["Type_"+onSaleType](originTotal,account)

//执行
getActualTotal(0,2680.00);//2208

分析上面的代码我们发现,不管促销策略如何增加,getActualTotal函数完全不需要再变化了。我们要做的,就是增加新策略的函数而已。

通过策略模式的代码,我们消除了让人反胃的大片条件分支语句,getActualTotal本身并没有计算能力,而是将计算全权委托给了策略函数。

由此我们可以总结出策略模式实现的要点:

  1. 将变化的算法封装成独立的策略函数,并负责具体的计算
  2. 委托函数,该函数接受客户请求,并将请求委托给某一个具体的策略函数

用一张UML图表示如下:
技术分享图片

怎么样?现在看到上面这张图是不是有了了然于胸的感觉?那就赶紧去试一试策略模式吧!


参考书籍:

  1. 《设计模式:可复用面向对象软件的基础》
  2. 《大话设计模式》
  3. 《Javascript设计模式与开发实践》


设计模式之策略模式(行为型)(代码片段)

一、模式定义策略模式:定义一系列算法,然后将每一个算法封装起来,并将它们可以互相替换。也就是将一系列算法封装到一系列策略类里面。策略模式是一种对象行为型模式。策略模式符合“开闭原则“StrategyPattern:Defineafami... 查看详情

设计模式之策略模式(代码片段)

策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用不同的算法,减少了各种算法类与使用算法类之间的耦合。1|策略模式定义策略模式是一种... 查看详情

javascript设计模式之策略模式(代码片段)

...一个个封装起来。将不变的部分和变化的部分隔开是每个设计模式的主题,策略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来。策略模式的实现并不复杂,关键是如何从策略模式的实现 查看详情

大话设计模式之策略模式读后感(代码片段)

策略模式:定义了算法家族,分别封装起来,让他们呢之间可以互相的替换,此模式让算法的变化不会影响到使用算法的客户。UML类图:解读:策略模式是定义一系列的算法,从概念上来讲,这些算法完成的工作都是一样的,只... 查看详情

设计模式之策略模式(代码片段)

...例1.简要概述策略模式也叫作决策模式,属于行为型设计模式。策略模式定义了解决某一个问题的一个算法族,允许用户从该算法族中针对不同的场景选择一个算法解决该问题,同时可以方便的更换算法或者增加新的... 查看详情

接口抽象类应用之策略模式学习(代码片段)

接口应用之策略模式策略模式(StrategyPattern),定义了一系列算法,将每一种算法封装起来并可以相互替换使用,策略模式让算法独立于它的客户应用而独立变化。OO设计原则面向接口编程(面向抽象编程)封装变化多用组合,... 查看详情

设计模式之策略模式(代码片段)

设计模式之策略模式1.意图根据GOF的定义:定义一系列的算法或操作,并把它们一个个封装起来,并且使它们可以互换替换。以达到算法与业务独立开发的目的。简单的说就是针对某个业务需求,抽象出解决问题的算法的一个个... 查看详情

设计模式之策略模式(strategy)详解及代码示例(代码片段)

一、策略模式的定义  策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把... 查看详情

设计模式之策略模式(代码片段)

首先看定义,策略模式:策略模式定义了一系列算法,并将每一个算法封装起来,且使它们可以互相替换,此模式让算法的变化独立于使用算法的客户端。我的理解就是,分装起来的算法要实现相互替换,则说明这些算法是具有... 查看详情

设计模式之策略模式(代码片段)

一.应用背景   在软件开发中常常遇到这种情况,实现某一个功能有多种算法或者策略,我们可以根据应用场景的不同选择不同的算法或者策略来完成该功能。把一个类(A)中经常改变或者将来可能改变的部分提取出来... 查看详情

设计模式之策略模式(代码片段)

概要设计模式是一门艺术,如果真正了解这门艺术,你会发现,世界都将变得更加优美。定义策略模式定义了一系列的算法,并将每一个算法封装起来,他们之间还可以相互替换,策略模式独立于使用它的... 查看详情

23种设计模式之策略模式——strategy(代码片段)

Strategy--策略模式程序员看问题需要有时间轴的概念,静态可能暴露不出问题,要动态的看。看问题要加上时间轴。一、定义定义一系列算法,把它们一个个封装起来,并且使它们互相替换(变化),该模式使得算法可独立于使... 查看详情

设计模式学习笔记之策略模式(代码片段)

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。(来自百度的定义)单从概念上看总觉得晕乎乎的,下面我们来看一个小例子... 查看详情

javascript设计模式之策略模式(代码片段)

...一个个封装起来。将不变的部分和变化的部分隔开是每个设计模式的主题,策略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来。策略模式的实现并不复杂,关键是如何从策略模式的实现背后... 查看详情

java设计模式之策略学习与掌握(代码片段)

...结构与实现模式的结构模式的实现应用场景前言个人建议设计模式这一系列的文章,多关注定义和模式的代码实现。至于模式结构和扩展或者是应用场景,基本了解过一下就好,没必要硬记。这只是我的个人建议࿰... 查看详情

设计模式系列——策略模式(代码片段)

原创:花括号MC(微信公众号:huakuohao-mc)。关注JAVA基础编程及大数据,注重经验分享及个人成长。策略模式常用于一个对象的行为在运行时有多个不同的策略和算法。举个例子可以通过实现一个加、减、乘三种不用策略的运算,... 查看详情

设计模式之-策略模式(strategypattern)(代码片段)

...,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的context对象。策略对象改变context对象的执行算法。 C++实... 查看详情

设计模式之策略模式(代码片段)

设计模式之策略模式  策略模式(StraregyPattern)是一种比较简单的模式,也叫政策模式(PolicyPattern),定义如下:Defineafamilyofalgorithms,encapsulateeachone,andmaketheminterchangeable.(定义一组算法,将每个算法都封装起来,并... 查看详情