Heim  >  Artikel  >  Web-Frontend  >  Erlernen Sie JavaScript-Entwurfsmuster (Strategiemuster)_Javascript-Kenntnisse

Erlernen Sie JavaScript-Entwurfsmuster (Strategiemuster)_Javascript-Kenntnisse

WBOY
WBOYOriginal
2016-05-16 15:29:401037Durchsuche

Was ist Strategie? Wenn wir beispielsweise irgendwohin reisen möchten, können wir die Route basierend auf der tatsächlichen Situation auswählen.
1. Definition des Strategiemusters

Wenn Sie keine Zeit haben, sich aber nicht um Geld kümmern, können Sie sich für einen Flug entscheiden.
Wenn Sie kein Geld haben, können Sie Bus oder Bahn nehmen.
Wenn Sie ärmer sind, können Sie sich für das Fahrradfahren entscheiden.
Beim Programmieren stoßen wir häufig auf ähnliche Situationen. Es stehen viele Optionen zur Auswahl, um eine bestimmte Funktion zu implementieren. Beispielsweise kann ein Programm, das Dateien komprimiert, entweder den Zip-Algorithmus oder den Gzip-Algorithmus wählen.

Definition: Das Strategiemuster definiert eine Reihe von Algorithmen, die separat gekapselt sind, sodass sie untereinander ersetzt werden können. Dieses Muster macht die Algorithmusänderungen unabhängig von den Kunden die Suanfan verwenden.

Das Strategiemuster hat ein breites Anwendungsspektrum. In diesem Abschnitt nehmen wir die Berechnung des Jahresendbonus als Beispiel.

2. Beispiele für Jahresendboni

Die Jahresendprämien vieler Unternehmen basieren auf der Gehaltsbasis und der Leistung der Mitarbeiter am Jahresende. Beispielsweise beträgt der Jahresendbonus einer Person mit Leistung S das Vierfache des Gehalts, der Jahresendbonus einer Person mit Leistung A das Dreifache des Gehalts und der Jahresendbonus einer Person mit Leistung B das Dreifache des Gehalts 2-faches Gehalt. Angenommen, die Finanzabteilung bittet uns um die Bereitstellung eines Codes, um die Berechnung der Jahresendboni der Mitarbeiter zu erleichtern.

1). Erste Code-Implementierung

Wir können eine Funktion namens „calchBonus“ schreiben, um den Bonusbetrag für jede Person zu berechnen. Damit die Funktion „calculeBonus“ korrekt funktioniert, muss sie natürlich zwei Parameter erhalten: den Gehaltsbetrag des Mitarbeiters und seine Leistungsbeurteilungsnote. Der Code lautet wie folgt:

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

Es kann festgestellt werden, dass dieser Code sehr einfach ist, aber offensichtliche Mängel aufweist.

calculateBonus-Funktion ist relativ groß, enthält viele if-else-Anweisungen, die alle logischen Zweige abdecken müssen.

Die berechneBonus-Funktion ist unflexibel. Wenn eine neue Leistungsstufe C hinzugefügt wird oder wir den Bonuskoeffizienten der Leistung S auf 5 ändern möchten, müssen wir tief in die interne Implementierung von berechneBonus einsteigen Funktion, die eine Verletzung des Offen-Geschlossen-Prinzips darstellt.

Die Wiederverwendbarkeit des Algorithmus ist schlecht. Was passiert, wenn diese Algorithmen zur Berechnung von Boni an anderer Stelle im Programm wiederverwendet werden müssen? Unsere einzigen Optionen sind Kopieren und Einfügen. Daher müssen wir diesen Code umgestalten.

2). Refaktorieren Sie den Code mithilfe kombinierter Funktionen

Im Allgemeinen ist es am einfachsten, Kombinationsfunktionen zu verwenden, um sie zu rekonstruieren. Diese kleinen Funktionen sind gut benannt und Sie können auf einen Blick erkennen, welchem ​​Algorithmus sie entsprechen können auch an anderer Stelle im Programm wiederverwendet werden. Der Code lautet wie folgt:

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

Derzeit wurde unser Programm in gewissem Maße verbessert, aber diese Verbesserung ist sehr begrenzt. Wir haben das wichtigste Problem immer noch nicht gelöst: Die Funktion „calcureBonus“ wird möglicherweise immer größer und es mangelt ihr an Flexibilität, wenn sich das System ändert.

3). Verwenden Sie das Strategiemuster, um Code umzugestalten

Nachdem wir darüber nachgedacht hatten, kamen wir auf einen besseren Weg – die Verwendung von Strategiemustern zur Umgestaltung des Codes. Das Strategiemuster bezieht sich auf die Definition einer Reihe von Algorithmen und deren Kapselung nacheinander. Die Trennung der unveränderten Teile von den sich ändernden Teilen ist das Thema jedes Entwurfsmusters, und das Strategiemuster bildet da keine Ausnahme. Der Zweck des Strategiemusters besteht darin, die Verwendung des Algorithmus von der Implementierung des Algorithmus zu trennen.

In diesem Beispiel bleibt die Methode zur Verwendung des Algorithmus dieselbe und der berechnete Bonusbetrag wird basierend auf einem bestimmten Algorithmus ermittelt. Die Implementierung von Algorithmen ist unterschiedlich und ändert sich, und jede Leistung entspricht unterschiedlichen Berechnungsregeln.

Ein auf dem Strategiemuster basierendes Programm besteht aus mindestens zwei Teilen. Der erste Teil besteht aus einer Reihe von Strategieklassen. Die Strategieklasse kapselt bestimmte Algorithmen und ist für den spezifischen Berechnungsprozess verantwortlich. Der zweite Teil ist die Umgebungsklasse Context. Context nimmt die Anfrage des Kunden an und delegiert die Anfrage dann an eine bestimmte Strategieklasse. Dazu muss im Kontext ein Verweis auf ein Richtlinienobjekt gepflegt werden.

Verwenden Sie nun das Strategiemuster, um den obigen Code umzugestalten. Die erste Version wurde nach der Implementierung in traditionellen objektorientierten Sprachen modelliert. Wir kapseln zunächst jede Leistungsberechnungsregel in der entsprechenden Strategieklasse:

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;
};

Als nächstes definieren Sie die Bonusart Bonus:

var Bonus = function(){
 this.salary = null; //原始工资
 this.strategy = null; //绩效等级对应的策略对象
};

Bonus.prototype.setSalary = function( salary ){
 this.salary = salary; //设置员工的原始工资
};

Bonus.prototype.setStrategy = function( strategy ){
 this.strategy = strategy; //设置员工绩效等级对应的策略对象
};

Bonus.prototype.getBonus = function(){ //取得奖金数额
 return this.strategy.calculate( this.salary ); //把计算奖金的操作委托给对应的策略对象
};

在完成最终的代码之前,我们再来回顾一下策略模式的思想:

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

这句话如果说得更详细一点,就是:定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里。在客户对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年要过去了,大家的年终奖是不是很丰厚呀!!!

希望大家可以在这一年里有所收获,通过这篇文章也能有所收获,知道什么是策略模式,理解小编精心为大家准备的两个实例。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn