프론트엔드에서 디자인 패턴 중 전략 패턴을 활용하는 방법
이번에는 Design Pattern의 Strategy Pattern을 프론트엔드에서 어떻게 사용하는지, 그리고 Design Pattern의 Strategy Pattern을 프론트엔드에서 사용할 때 주의사항에 대해 알려드리겠습니다. 실제 사례를 살펴보겠습니다.
전략 모드란 무엇인가요?
4명의 GoF 형제가 쓴 고전적인 "디자인 패턴"에서 전략 패턴은 다음과 같이 정의됩니다.
일련의 알고리즘을 정의하고 이를 하나씩 캡슐화하고 상호 교환 가능하게 만듭니다.
위 문장은 말 그대로 매우 간단합니다. 하지만 이를 개발 과정에 어떻게 적용할지 여전히 하나의 정의만으로는 혼란스럽습니다. 저자가 한때 작업했던 상인 구매, 판매 및 재고 시스템을 예로 들어 보겠습니다.
한 슈퍼마켓에서 프로모션을 준비하고 있습니다. 조사 및 분석 후 시장 직원은 몇 가지 프로모션 전략을 세웠습니다. 100개 이상 구매
200개 이상 구매 시 30 할인
50 할인
300개 이상 구매 시. . .
캐셔 소프트웨어의 인터페이스는 다음과 같습니다(간단한 다이어그램).
초기 구현은 다음과 같습니다.
//方便起见,我们把各个促销策略定义为枚举值: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,有人说我很懒,虽然这样不够优雅但并不影响我的使用,毕竟满减策略再多也多不到哪去。
我只能说,需求永远不是程序员定的。。这时,市场人员说我们新版程序添加了会员功能,我们需要支持以下的促销策略:
会员促销策略:
会员充300返60,且首单打9折
会员充500返100,且首单打8折
会员充1000返300,且首单打7折
...
这个时候,如果你还在原先的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; } }
好了,现在我们每种策略都有自己独立的空间了,看起来井井有条。但是还有两个问题没有解决:
随着促销策略的增加,
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
- 회원 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
자체에는 컴퓨팅 성능이 없지만 계산을 전략 함수에 위임합니다. 🎜🎜이로부터 전략 패턴 구현의 핵심 사항을 요약할 수 있습니다. 🎜🎜🎜🎜변화하는 알고리즘을 독립적인 전략 함수로 캡슐화하고 특정 계산을 담당합니다🎜 고객 요청을 받아들여 특정 전략 기능에 위임하는 위임 기능
을 UML 다이어그램으로 표현하면 다음과 같습니다.
어때요? 이제 위의 사진을 보셨으니 확실히 이해가 되셨나요? 그렇다면 서둘러서 전략 모드를 플레이해 보세요!
참고 도서:
"디자인 패턴: 재사용 가능객체 지향소프트웨어의 기초"
"Dahua 디자인 패턴"
"J avascript 디자인 패턴 및 개발 연습》
저는 수년간 프론트엔드 개발을 해왔지만 디자인 패턴을 깊이있게 연구하고 정리한 적이 없습니다. 건축 관련 작업을 하다 보니 디자인 패턴이 제가 앞으로 나아가는 데 걸림돌이 된다는 걸 점점 더 많이 느껴요. 그러니 오늘부터 고전적인 디자인 패턴과 몇 가지 주요 객체지향 원칙을 깊이 연구하고 요약해 보세요.
오늘 첫날에는 먼저 전략 모드에 대해 이야기해보겠습니다.
전략 모드란 무엇인가요?
4명의 GoF 형제가 쓴 고전적인 "디자인 패턴"에서 전략 패턴은 다음과 같이 정의됩니다.
일련의 알고리즘을 정의하고 이를 하나씩 캡슐화하고 상호 교환 가능하게 만듭니다.
위 문장은 말 그대로 매우 간단합니다. 하지만 이를 개발 과정에 어떻게 적용할지 여전히 하나의 정의만으로는 혼란스럽습니다. 저자가 한때 작업했던 상인 구매, 판매 및 재고 시스템을 예로 들어 보겠습니다.
한 슈퍼마켓에서 프로모션을 준비하고 있습니다. 조사 및 분석 후 시장 직원은 몇 가지 프로모션 전략을 세웠습니다. 100개 이상 구매
200개 이상 구매 시 30 할인
50 할인
300개 이상 구매 시. . .
캐셔 소프트웨어의 인터페이스는 다음과 같습니다(간단한 다이어그램).
초기 구현은 다음과 같습니다.
//方便起见,我们把各个促销策略定义为枚举值: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,有人说我很懒,虽然这样不够优雅但并不影响我的使用,毕竟满减策略再多也多不到哪去。
我只能说,需求永远不是程序员定的。。这时,市场人员说我们新版程序添加了会员功能,我们需要支持以下的促销策略:
会员促销策略:
会员充300返60,且首单打9折
会员充500返100,且首单打8折
会员充1000返300,且首单打7折
...
这个时候,如果你还在原先的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; } }
好了,现在我们每种策略都有自己独立的空间了,看起来井井有条。但是还有两个问题没有解决:
随着促销策略的增加,
getActualTotal
的代码量依然会越来越大系统缺乏弹性,如果需要增加一种策略,那么除了添加一个策略函数,还需要修改
switch...case..
회원 500충전 100백, 첫 주문 20% 할인
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
本身并没有计算能力,而是将计算全权委托给了策略函数。
由此我们可以总结出策略模式实现的要点:
将变化的算法封装成独立的策略函数,并负责具体的计算
委托函数,该函数接受客户请求,并将请求委托给某一个具体的策略函数
用一张UML图表示如下:
怎么样?现在看到上面这张图是不是有了了然于胸的感觉?那就赶紧去试一试策略模式吧!
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 프론트엔드에서 디자인 패턴 중 전략 패턴을 활용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Java 프레임워크에서 디자인 패턴과 아키텍처 패턴의 차이점은 디자인 패턴이 클래스와 객체(예: 팩토리 패턴) 간의 상호 작용에 중점을 두고 소프트웨어 디자인의 일반적인 문제에 대한 추상적인 솔루션을 정의한다는 것입니다. 아키텍처 패턴은 계층화된 아키텍처와 같은 시스템 구성 요소의 구성 및 상호 작용에 중점을 두고 시스템 구조와 모듈 간의 관계를 정의합니다.

어댑터 패턴은 호환되지 않는 개체가 함께 작동할 수 있도록 하는 구조적 디자인 패턴입니다. 이는 개체가 원활하게 상호 작용할 수 있도록 하나의 인터페이스를 다른 인터페이스로 변환합니다. 개체 어댑터는 적응된 개체를 포함하는 어댑터 개체를 만들고 대상 인터페이스를 구현하여 어댑터 패턴을 구현합니다. 실제적인 경우 클라이언트(예: MediaPlayer)는 어댑터 모드를 통해 고급 형식 미디어(예: VLC)를 재생할 수 있지만 클라이언트 자체는 일반 미디어 형식(예: MP3)만 지원합니다.

데코레이터 패턴은 원래 클래스를 수정하지 않고도 객체 기능을 동적으로 추가할 수 있는 구조적 디자인 패턴입니다. 추상 컴포넌트, 콘크리트 컴포넌트, 추상 데코레이터, 콘크리트 데코레이터의 협업을 통해 구현되며, 변화하는 요구에 맞게 클래스 기능을 유연하게 확장할 수 있습니다. 이 예에서는 우유와 모카 데코레이터가 총 $2.29의 가격으로 Espresso에 추가되어 객체의 동작을 동적으로 수정하는 데코레이터 패턴의 힘을 보여줍니다.

1. 팩토리 패턴: 객체 생성과 비즈니스 로직을 분리하고, 팩토리 클래스를 통해 지정된 형태의 객체를 생성합니다. 2. 관찰자 패턴: 주체 개체가 관찰자 개체에 상태 변경을 알리도록 허용하여 느슨한 결합 및 관찰자 패턴을 달성합니다.

디자인 패턴은 재사용 및 확장 가능한 솔루션을 제공하여 코드 유지 관리 문제를 해결합니다. 관찰자 패턴: 개체가 이벤트를 구독하고 이벤트가 발생할 때 알림을 받을 수 있도록 합니다. 팩토리 패턴: 구체적인 클래스에 의존하지 않고 객체를 생성하는 중앙 집중식 방법을 제공합니다. 싱글톤 패턴: 클래스에 전역적으로 액세스 가능한 개체를 만드는 데 사용되는 인스턴스가 하나만 있는지 확인합니다.

TDD는 고품질 PHP 코드를 작성하는 데 사용됩니다. 단계에는 테스트 사례 작성, 예상 기능 설명 및 실패 만들기가 포함됩니다. 과도한 최적화나 세부 설계 없이 테스트 케이스만 통과하도록 코드를 작성합니다. 테스트 케이스를 통과한 후 코드를 최적화하고 리팩터링하여 가독성, 유지 관리성 및 확장성을 향상시킵니다.

Java 프레임워크에서 디자인 패턴을 사용하면 향상된 코드 가독성, 유지 관리성 및 확장성이 향상된다는 이점이 있습니다. 단점으로는 복잡성, 성능 오버헤드, 과도한 사용으로 인한 가파른 학습 곡선 등이 있습니다. 실제 사례: 프록시 모드는 개체를 지연 로드하는 데 사용됩니다. 디자인 패턴을 현명하게 사용하여 장점을 활용하고 단점을 최소화하세요.

Guice 프레임워크는 다음을 포함한 다양한 디자인 패턴을 적용합니다. 싱글톤 패턴: @Singleton 주석을 통해 클래스에 인스턴스가 하나만 있는지 확인합니다. 팩토리 메소드 패턴: @Provides 주석을 통해 팩토리 메소드를 생성하고 종속성 주입 중에 객체 인스턴스를 얻습니다. 전략 모드: 알고리즘을 다양한 전략 클래스로 캡슐화하고 @Named 주석을 통해 특정 전략을 지정합니다.
