프론트엔드에서 디자인 패턴 중 전략 패턴을 활용하는 방법

php中世界最好的语言
풀어 주다: 2018-05-24 09:50:30
원래의
1314명이 탐색했습니다.

이번에는 Design PatternStrategy Pattern을 프론트엔드에서 어떻게 사용하는지, 그리고 Design Pattern의 Strategy Pattern을 프론트엔드에서 사용할 때 주의사항에 대해 알려드리겠습니다. 실제 사례를 살펴보겠습니다.

전략 모드란 무엇인가요?

4명의 GoF 형제가 쓴 고전적인 "디자인 패턴"에서 전략 패턴은 다음과 같이 정의됩니다.

일련의 알고리즘을 정의하고 이를 하나씩 캡슐화하고 상호 교환 가능하게 만듭니다.

위 문장은 말 그대로 매우 간단합니다. 하지만 이를 개발 과정에 어떻게 적용할지 여전히 하나의 정의만으로는 혼란스럽습니다. 저자가 한때 작업했던 상인 구매, 판매 및 재고 시스템을 예로 들어 보겠습니다.

한 슈퍼마켓에서 프로모션을 준비하고 있습니다. 조사 및 분석 후 시장 직원은 몇 가지 프로모션 전략을 세웠습니다. 100개 이상 구매
  1. 200개 이상 구매 시 30 할인

  2. 50 할인

  3. 300개 이상 구매 시. . .

  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 판단으로 가득 차 있으므로 주의하지 않으면 실수하기 쉽습니다. .

좋아요, 일부 사람들은 제가 게으르다고 말합니다. 비록 이것이 충분히 우아하지는 않지만 결국에는 전체 축소 전략을 아무리 많이 사용해도 충분하지 않습니다.
요구사항은 결코 프로그래머에 의해 결정되지 않는다고 말씀드릴 수 있습니다. . 현재 마켓 직원은 새로운 버전의 프로그램에 멤버십 기능이 추가되었으며 다음과 같은 프로모션 전략을 지원해야 한다고 말했습니다. 그리고 첫 주문 10% 할인

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

회원 500충전 100백, 첫 주문 20% 할인

  1. 회원 1000충전하고 300환급, 첫 주문 30% 할인

    🎜🎜...🎜🎜🎜🎜이때, 아직 원본 getActualTotal에 있다면 계속해서 if 판단을 함수에 추가해 주시면 될 것 같습니다. 당신의 코드를 보면 그는 애초에 왜 당신을 고용했는지 궁금해할 것입니다. . 🎜🎜자, 마침내 프로모션 전략의 코드를 리팩토링하기로 결정했습니다. 다음과 같이 할 수 있습니다. 🎜
    //方便起见,我们把各个促销策略定义为枚举值: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의 코드 볼륨은 계속해서 커질 것입니다.🎜🎜🎜🎜시스템의 유연성이 부족합니다. 전략을 추가해야 한다면 전략 함수를 추가하는 것 외에도 switch...case.. 문도 수정해야 합니다🎜🎜🎜🎜전략의 정의를 검토해 보겠습니다. 패턴: 🎜🎜일련의 알고리즘을 정의합니다. 이는 하나씩 캡슐화되어 상호 교환 가능합니다. 이 예에서는 각 프로모션 전략의 구현이 다르지만 최종 목표는 실제 금액을 찾는 것입니다. 전략 패턴은 판촉 전략에 대한 알고리즘을 하나씩 캡슐화하고 실제 금액 평가에 영향을 주지 않으면서 상호 교환이 가능하도록 만들 수 있습니다. 이것이 바로 우리에게 필요한 것입니다. 🎜🎜 전략 패턴을 사용하여 위 코드를 재구성해 보겠습니다. 🎜
    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;
        }
    }
    로그인 후 복사
    로그인 후 복사
    로그인 후 복사
    🎜 위 코드를 분석한 결과 프로모션 전략이 아무리 높아져도 getActualTotal 함수는 전혀 변경할 필요가 없다는 사실을 발견했습니다. . 우리가 해야 할 일은 새로운 전략의 기능을 추가하는 것뿐입니다. 🎜🎜전략 패턴 코드를 통해 우리는 위태로운 조건 분기 문을 제거합니다. getActualTotal 자체에는 컴퓨팅 성능이 없지만 계산을 전략 함수에 위임합니다. 🎜🎜이로부터 전략 패턴 구현의 핵심 사항을 요약할 수 있습니다. 🎜🎜🎜🎜변화하는 알고리즘을 독립적인 전략 함수로 캡슐화하고 특정 계산을 담당합니다🎜
  2. 고객 요청을 받아들여 특정 전략 기능에 위임하는 위임 기능

을 UML 다이어그램으로 표현하면 다음과 같습니다.
프론트엔드에서 디자인 패턴 중 전략 패턴을 활용하는 방법

어때요? 이제 위의 사진을 보셨으니 확실히 이해가 되셨나요? 그렇다면 서둘러서 전략 모드를 플레이해 보세요!


참고 도서:

  1. "디자인 패턴: 재사용 가능객체 지향소프트웨어의 기초"

  2. "Dahua 디자인 패턴"

  3. "J avascript 디자인 패턴 및 개발 연습》

저는 수년간 프론트엔드 개발을 해왔지만 디자인 패턴을 깊이있게 연구하고 정리한 적이 없습니다. 건축 관련 작업을 하다 보니 디자인 패턴이 제가 앞으로 나아가는 데 걸림돌이 된다는 걸 점점 더 많이 느껴요. 그러니 오늘부터 고전적인 디자인 패턴과 몇 가지 주요 객체지향 원칙을 깊이 연구하고 요약해 보세요.

오늘 첫날에는 먼저 전략 모드에 대해 이야기해보겠습니다.

전략 모드란 무엇인가요?

4명의 GoF 형제가 쓴 고전적인 "디자인 패턴"에서 전략 패턴은 다음과 같이 정의됩니다.

일련의 알고리즘을 정의하고 이를 하나씩 캡슐화하고 상호 교환 가능하게 만듭니다.

위 문장은 말 그대로 매우 간단합니다. 하지만 이를 개발 과정에 어떻게 적용할지 여전히 하나의 정의만으로는 혼란스럽습니다. 저자가 한때 작업했던 상인 구매, 판매 및 재고 시스템을 예로 들어 보겠습니다.

한 슈퍼마켓에서 프로모션을 준비하고 있습니다. 조사 및 분석 후 시장 직원은 몇 가지 프로모션 전략을 세웠습니다. 100개 이상 구매
  1. 200개 이상 구매 시 30 할인

  2. 50 할인

  3. 300개 이상 구매 시. . .

  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 판단으로 가득 차 있으므로 주의하지 않으면 실수하기 쉽습니다. .

좋아요, 일부 사람들은 제가 게으르다고 말합니다. 비록 이것이 충분히 우아하지는 않지만 결국에는 전체 축소 전략을 아무리 많이 사용해도 충분하지 않습니다.

요구사항은 결코 프로그래머에 의해 결정되지 않는다고 말씀드릴 수 있습니다. . 현재 마켓 직원은 새로운 버전의 프로그램에 멤버십 기능이 추가되었으며 다음과 같은 프로모션 전략을 지원해야 한다고 말했습니다. 그리고 첫 주문 10% 할인

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..

  3. 회원 500충전 100백, 첫 주문 20% 할인

🎜회원 1000충전하고 300환급, 첫 주문 30% 할인🎜🎜 🎜🎜...🎜🎜🎜🎜이때, 아직 원본 getActualTotal에 있다면 계속해서 if 판단을 함수에 추가해 주시면 될 것 같습니다. 당신의 코드를 보면 그는 애초에 왜 당신을 고용했는지 궁금해할 것입니다. . 🎜🎜자, 마침내 프로모션 전략의 코드를 리팩토링하기로 결정했습니다. 다음과 같이 할 수 있습니다. 🎜
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의 코드 볼륨은 계속해서 커질 것입니다.🎜🎜🎜🎜시스템의 유연성이 부족합니다. 전략을 추가해야 하는 경우 전략 기능을 추가하는 것 외에도 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图表示如下:
프론트엔드에서 디자인 패턴 중 전략 패턴을 활용하는 방법

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

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样使用JS+H5实现微信摇一摇

如何对微信小程序进行开发

위 내용은 프론트엔드에서 디자인 패턴 중 전략 패턴을 활용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!