자바스크립트 디자인 패턴(전략 패턴)_javascript 기술 배우기
전략이란 무엇인가? 예를 들어, 어딘가로 여행을 가고 싶다면 실제 상황에 따라 경로를 선택할 수 있습니다.
1. 전략 패턴의 정의
시간은 없지만 돈에 관심이 없다면 비행기를 선택할 수 있습니다.
돈이 없다면 버스나 기차를 이용할 수 있습니다.
가난하다면 자전거를 타는 것을 선택할 수 있습니다.
프로그래밍에서 특정 기능을 구현하기 위해 선택할 수 있는 옵션이 많이 있습니다. 예를 들어, 파일을 압축하는 프로그램은 zip 알고리즘이나 gzip 알고리즘을 선택할 수 있습니다.
정의: 전략 패턴은 서로 교체할 수 있도록 별도로 캡슐화되는 일련의 알고리즘을 정의합니다. 이 패턴은 알고리즘 변경을 고객과 독립적으로 만듭니다. 수안팬을 이용하시는 분.
전략 패턴은 다양한 용도로 사용됩니다. 이번 장에서는 연말 보너스 계산을 예로 들어보겠습니다.
2. 연말 보너스 예시
많은 회사의 연말 상여금은 직원의 급여 기반과 연말 성과에 따라 결정됩니다. 예를 들어 성과 S의 연말 상여금은 연봉의 4배, 성과 A의 연말 상여금은 연봉의 3배, 성과 B의 연말 상여금은 급여의 2배. 재무 부서에서 직원의 연말 보너스 계산을 용이하게 하기 위해 코드 조각을 제공하도록 요청한다고 가정해 보겠습니다.
1) 초기 코드 구현
calculateBonus라는 함수를 작성하여 각 사람의 보너스 금액을 계산할 수 있습니다. 분명히calculateBonus 함수가 올바르게 작동하려면 직원의 급여 금액과 성과 평가 등급이라는 두 가지 매개 변수를 받아야 합니다. 코드는 다음과 같습니다.
var calculateBonus = function( performanceLevel, salary ){ if ( performanceLevel === 'S' ){ return salary * 4; } if ( performanceLevel === 'A' ){ return salary * 3; } if ( performanceLevel === 'B' ){ return salary * 2; } }; calculateBonus( 'B', 20000 ); // 输出:40000 calculateBonus( 'S', 6000 ); // 输出:24000
이 코드는 매우 간단하지만 분명한 단점이 있다는 것을 알 수 있습니다.
calculateBonus 함수는 비교적 크고, 에는 모든 논리적 분기를 포괄해야 하는 많은 if-else 문이 포함되어 있습니다.
<… 이는 개방-폐쇄 원칙을 위반하는 기능입니다.알고리즘의 재사용성이 좋지 않습니다. 보너스 계산을 위한 이러한 알고리즘을 프로그램의 다른 곳에서 재사용해야 한다면 어떻게 될까요? 유일한 옵션은 복사하여 붙여넣는 것입니다. 따라서 이 코드를 리팩터링해야 합니다.
2) 결합된 함수를 사용하여 코드를 리팩터링합니다일반적으로 생각하기 가장 쉬운 방법은 조합 함수를 사용하여 재구성하는 것입니다. 이러한 작은 함수는 이름이 잘 지정되어 있으며 어떤 알고리즘에 해당하는지 한눈에 알 수 있습니다. 프로그램의 다른 곳에서도 재사용할 수 있습니다. 코드는 다음과 같습니다.
var performanceS = function( salary ){ return salary * 4; }; var performanceA = function( salary ){ return salary * 3; }; var performanceB = function( salary ){ return salary * 2; }; var calculateBonus = function( performanceLevel, salary ){ if ( performanceLevel === 'S' ){ return performanceS( salary ); } if ( performanceLevel === 'A' ){ return performanceA( salary ); } if ( performanceLevel === 'B' ){ return performanceB( salary ); } }; calculateBonus( 'A' , 10000 ); // 输出:30000
고심 끝에 전략 패턴을 사용하여 코드를 리팩터링하는 더 나은 방법을 생각해냈습니다. 전략 패턴은 일련의 알고리즘을 정의하고 이를 하나씩 캡슐화하는 것을 의미합니다. 변하지 않는 부분과 변화하는 부분을 분리하는 것은 모든 디자인 패턴의 주제이며, 전략 패턴도 예외는 아닙니다. 전략 패턴의 목적은 알고리즘의 사용과 알고리즘의 구현을 분리하는 것입니다.
이 예시에서는 알고리즘을 사용하는 방법은 동일하며 특정 알고리즘을 기반으로 계산된 보너스 금액을 얻습니다. 알고리즘의 구현은 다양하고 변화하며 각 성능은 서로 다른 계산 규칙에 해당합니다.전략 패턴에 기반한 프로그램은 적어도 두 부분으로 구성됩니다. 첫 번째 부분은 전략 클래스 세트입니다. 전략 클래스는 특정 알고리즘을 캡슐화하고 특정 계산 프로세스를 담당합니다. 두 번째 부분은 환경 클래스 Context입니다. Context는 고객의 요청을 수락한 다음 해당 요청을 특정 전략 클래스에 위임합니다. 이를 위해서는 정책 개체에 대한 참조가 컨텍스트에서 유지되어야 함을 의미합니다.
이제 전략 패턴을 사용하여 위 코드를 리팩터링합니다. 첫 번째 버전은 전통적인 객체 지향 언어로 구현된 후 모델링되었습니다. 먼저 해당 전략 클래스에 각 성과 계산 규칙을 캡슐화합니다.
var performanceS = function(){}; performanceS.prototype.calculate = function( salary ){ return salary * 4; }; var performanceA = function(){}; performanceA.prototype.calculate = function( salary ){ return salary * 3; }; var performanceB = function(){}; performanceB.prototype.calculate = function( salary ){ return salary * 2; };
在完成最终的代码之前,我们再来回顾一下策略模式的思想:
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
这句话如果说得更详细一点,就是:定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里。在客户对Context发起请求的时候,Context总是把请求委托给这些策略对象中间的某一个进行计算。
“并且使它们可以相互替换”,这句话在很大程度上是相对于静态类型语言而言的。因为静态类型语言中有类型检查机制,所以各个策略类需要实现同样的接口。当它们的真正类型被隐藏在接口后面时,它们才能被相互替换。而在JavaScript这种“类型模糊”的语言中没有这种困扰,任何对象都可以被替换使用。因此,JavaScript中的“可以相互替换使用”表现为它们具有相同的目标和意图。
现在我们来完成这个例子中剩下的代码。先创建一个bonus对象,并且给bonus对象设置一些原始的数据,比如员工的原始工资数额。接下来把某个计算奖金的策略对象也传入bonus对象内部保存起来。当调用bonus.getBonus()来计算奖金的时候,bonus对象本身并没有能力进行计算,而是把请求委托给了之前保存好的策略对象:
var bonus = new Bonus(); bonus.setSalary( 10000 ); bonus.setStrategy( new performanceS() ); //设置策略对象 console.log( bonus.getBonus() ); // 输出:40000 bonus.setStrategy( new performanceA() ); //设置策略对象 console.log( bonus.getBonus() ); // 输出:30000
刚刚我们用策略模式重构了这段计算年终奖的代码,可以看到通过策略模式重构之后,代码变得更加清晰,各个类的职责更加鲜明。但这段代码是基于传统面向对象语言的模仿,下一节我们将了解用JavaScript实现的策略模式。
在5.1节中,我们让strategy对象从各个策略类中创建而来,这是模拟一些传统面向对象语言的实现。实际上在JavaScript语言中,函数也是对象,所以更简单和直接的做法是把strategy直接定义为函数:
var strategies = { "S": function( salary ){ return salary * 4; }, "A": function( salary ){ return salary * 3; }, "B": function( salary ){ return salary * 2; } };
同样,Context也没有必要必须用Bonus类来表示,我们依然用calculateBonus 函数充当Context来接受用户的请求。经过改造,代码的结构变得更加简洁:
var strategies = { "S": function( salary ){ return salary * 4; }, "A": function( salary ){ return salary * 3; }, "B": function( salary ){ return salary * 2; } }; var calculateBonus = function( level, salary ){ return strategies[ level ]( salary ); }; console.log( calculateBonus( 'S', 20000 ) ); // 输出: 80000 console.log( calculateBonus( 'A', 10000 ) ); // 输出: 30000
3、实例再讲解
一个小例子就能让我们一目了然。
回忆下jquery里的animate方法.
$( div ).animate( {"left: 200px"}, 1000, 'linear' ); //匀速运动 $( div ).animate( {"left: 200px"}, 1000, 'cubic' ); //三次方的缓动
这2句代码都是让div在1000ms内往右移动200个像素. linear(匀速)和cubic(三次方缓动)就是一种策略模式的封装.
再来一个例子. 很多页面都会有个即时验证的表单. 表单的每个成员都会有一些不同的验证规则.
比如姓名框里面, 需要验证非空,敏感词,字符过长这几种情况。 当然是可以写3个if else来解决,不过这样写代码的扩展性和维护性可想而知。如果表单里面的元素多一点,需要校验的情况多一点,加起来写上百个if else也不是没有可能。
所以更好的做法是把每种验证规则都用策略模式单独的封装起来。需要哪种验证的时候只需要提供这个策略的名字。就像这样:
nameInput.addValidata({ notNull: true, dirtyWords: true, maxLength: 30 }) 而notNull,maxLength等方法只需要统一的返回true或者false,来表示是否通过了验证。 validataList = { notNull: function( value ){ return value !== ''; }, maxLength: function( value, maxLen ){ return value.length() > maxLen; } }
可以看到,各种验证规则很容易被修改和相互替换。如果某天产品经理建议字符过长的限制改成60个字符。那只需要0.5秒完成这次工作。
大概内容就为大家介绍到这。
聊一聊题外话,马上2015年要过去了,大家的年终奖是不是很丰厚呀!!!
希望大家可以在这一年里有所收获,通过这篇文章也能有所收获,知道什么是策略模式,理解小编精心为大家准备的两个实例。

핫 AI 도구

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

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

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

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

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

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

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

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

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

뜨거운 주제











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

Java 프레임워크의 전략 패턴은 클래스 동작을 동적으로 변경하는 데 사용됩니다. 특정 애플리케이션에는 다음이 포함됩니다. Spring 프레임워크: 데이터 유효성 검사 및 캐시 관리 JakartaEE 프레임워크: 트랜잭션 관리 및 종속성 주입 JSF 프레임워크: 변환기 및 유효성 검사기, 응답 수명 주기 관리

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

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

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

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

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

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