JavaScriptの戦略パターン

翻訳者から:

私は私のために新しい戦略パターンを研究するつもりでしたが、javascriptでのその実装の賢明なロシア語の記述を見つけませんでした。 wikiの記事はその複雑さを脅かしており、この例の可視性には多くの要望が残されています。 だからこそ、この記事の翻訳を取り上げ、同時にこのパターンが何であるかを理解しました。

ネタバレと灰色のテキストが私のコメントです。

次に、JavaScriptでSTRATEGYを使用する方法と、それを実際のライブラリで使用して小さな部分に分割する方法の例を見ていきます。


戦略パターンが大好きです。 可能な限りそれを使用しようとします。 基本的に、 委任を使用して、アルゴリズムを使用するクラスからアルゴリズムを分離します。



このアプローチにはいくつかの利点があります。

第一に、使用するアルゴリズムのバージョンを選択するための複雑な条件構造を回避します。

第二に、 接続性を弱め、それにより顧客の複雑さを軽減し、クラス集約を支持してサブクラスの拒否を促進します。

第三に、 モジュール性とテスト容易性が向上します。



STRATEGYの実装では、通常2人の参加者が使用されます。

以下:

戦略 -パターン自体。

戦略は、アルゴリズムの個別の実装です。



次に、JavascriptでSTRATEGYを使用する方法の例と、それを実際のライブラリで使用して小さな部分に分割する方法の例を見ていきます。



機能としての戦略

組み込みのFUNCTIONクラスはアルゴリズムをカプセル化する優れた方法を提供します。 そしてこれは、機能を戦略として使用できることを意味します。 関数をクライアントに渡して、クライアントがそれを使用することを確認してください。



これを例で説明します。 Greeterクラスを作成するとします。 彼の仕事は人々に挨拶することです。 また、 Greeterがさまざまな方法で挨拶できるようにしたいと考えています。 つまり、 アルゴリズムのいくつかの異なる実装が必要です 。 これを行うために、さまざまな挨拶戦略を作成します。 以下、 アルゴリズムは挨拶です。

// Greeter -  ,    . //         var Greeter = function(strategy) { this.strategy = strategy; }; // Greeter   greet, //       //  ,    Greeter.prototype.greet = function() { return this.strategy(); }; //     , //       //  : var politeGreetingStrategy = function() { console.log("Hello."); }; var friendlyGreetingStrategy = function() { console.log("Hey!"); }; var boredGreetingStrategy = function() { console.log("sup."); }; //   ! var politeGreeter = new Greeter(politeGreetingStrategy); var friendlyGreeter = new Greeter(friendlyGreetingStrategy); var boredGreeter = new Greeter(boredGreetingStrategy); console.log(politeGreeter.greet()); //=> Hello. console.log(friendlyGreeter.greet()); //=> Hey! console.log(boredGreeter.greet()); //=> sup.
      
      



このコードにエラーがあります( bashtannikに感謝します )。 コンソールへの出力はすでに戦略アルゴリズムでレイアウトされており、 greetメソッドは何も返さない関数を返すため、最後の3行を置き換える必要があります。
これら
 politeGreeter.greet(); //=> Hello. friendlyGreeter.greet(); //=> Hey! boredGreeter.greet(); //=> sup.
      
      





上記の例では、 Greeterクライアントと3つの異なる戦略を作成しました。 明らかに、 Greeterアルゴリズムの使用方法を知っていますが、その内部に何があるのか​​わかりません。



ただし、複雑なアルゴリズムの場合、多くの場合、機能だけでは十分ではありません。 この場合、OOPスタイルのSTRATEGYを使用することをお勧めします。



クラスとしての戦略

クラスは、特にアルゴリズムが上記の例で考案されたものよりも複雑な場合、 戦略にもなります。 クラスを使用すると、各戦略のインターフェイスを定義できます。



これを例として考えてください。

このコードは例の前にあることが暗示されています。
 var Greeter = function(strategy) { this.strategy = strategy; };
      
      



 //       Javascript //   ,      //     , //          . //    ,      var Strategy = function() {}; Strategy.prototype.execute = function() { throw new Error('Strategy#execute needs to be overridden.') }; //           //        `Strategy`. //  ,    , //      `execute` var GreetingStrategy = function() {}; GreetingStrategy.prototype = Object.create(Strategy.prototype); //   `execute`,       //    `Strategy`   . //  ,       . //      (Template Method). //      . GreetingStrategy.prototype.execute = function() { return this.sayHi() + this.sayBye(); }; GreetingStrategy.prototype.sayHi = function() { return "Hello, "; }; GreetingStrategy.prototype.sayBye = function() { return "Goodbye."; }; //      . //    -   `Greeter`. Greeter.prototype.greet = function() { return this.strategy.execute(); }; var greeter = new Greeter(new GreetingStrategy()); greeter.greet() //=> 'Hello, Goodbye.'
      
      



executeメソッドを使用してStrategyをオブジェクト(またはクラス)として定義しました。 クライアントは、このクラスに対応する任意の戦略を使用できます。



GreetingStrategyをチェックしてください。 最も興味深いのは、 executeメソッドのオーバーライドです。 このクラスの他のメソッドに依存します。 現在、このクラスを継承するオブジェクトは、メインアルゴリズムを変更せずにsayHisayByeなどの個々のメソッドを変更できます 。 このパターンはテンプレートメソッドと呼ばれ、 STRATEGYと完全に組み合わされます。



方法を見てみましょう。

 //   GreetingStrategy#execute    . //    ,     , //       ( `execute`) var PoliteGreetingStrategy = function() {}; PoliteGreetingStrategy.prototype = Object.create(GreetingStrategy.prototype); PoliteGreetingStrategy.prototype.sayHi = function() { return "Welcome sir, "; }; var FriendlyGreetingStrategy = function() {}; FriendlyGreetingStrategy.prototype = Object.create(GreetingStrategy.prototype); FriendlyGreetingStrategy.prototype.sayHi = function() { return "Hey, "; }; var BoredGreetingStrategy = function() {}; BoredGreetingStrategy.prototype = Object.create(GreetingStrategy.prototype); BoredGreetingStrategy.prototype.sayHi = function() { return "sup, "; }; var politeGreeter = new Greeter(new PoliteGreetingStrategy()); var friendlyGreeter = new Greeter(new FriendlyGreetingStrategy()); var boredGreeter = new Greeter(new BoredGreetingStrategy()); politeGreeter.greet(); //=> 'Welcome sir, Goodbye.' friendlyGreeter.greet(); //=> 'Hey, Goodbye.' boredGreeter.greet(); //=> 'sup, Goodbye.'
      
      



executeStrategyを定義することにより、 GreetingStrategyアルゴリズムのファミリーを作成します 。 上記のスニペットでは、いくつかの種類を作成することでこれを利用しました。



サブクラスを使用しなくても、 Greeterにポリモーフィズムがあります。 必要なアルゴリズムを呼び出すために別の種類のGreeterに切り替える必要はありません。 今、彼らはすべての新しいグリーターにいます。

 var greeters = [ new Greeter(new BoredGreetingStrategy()), new Greeter(new PoliteGreetingStrategy()), new Greeter(new FriendlyGreetingStrategy()), ]; greeters.forEach(function(greeter) { //    `greeter`     //      . //      `greet`, //        . greeter.greet(); });
      
      







実際のコードでの戦略

STRATEGIESを使用する私のお気に入りの例の1つは、 Passport.jsライブラリです。



Passport.jsは、node.jsで認証を管理する簡単な方法を提供します。 多数のプロバイダー(Facebook、Twitter、Googleなど)をサポートし、各プロバイダーは個別の戦略として提示されます。



このライブラリは、npmパッケージとそのすべての戦略として利用できます。 プログラマーは、この特定の場合にインストールするnpmパッケージを自由に決定できます。 これがどのように機能するかを示すコードの抜粋です。

 //    http://passportjs.org var passport = require('passport') //      npm-. //     . , LocalStrategy = require('passport-local').Strategy , FacebookStrategy = require('passport-facebook').Strategy; // Passport      . passport.use(new LocalStrategy( function(username, password, done) { User.findOne({ username: username }, function (err, user) { if (err) { return done(err); } if (!user) { return done(null, false, { message: 'Incorrect username.' }); } if (!user.validPassword(password)) { return done(null, false, { message: 'Incorrect password.' }); } return done(null, user); }); } )); // ,    Facebook passport.use(new FacebookStrategy({ clientID: FACEBOOK_APP_ID, clientSecret: FACEBOOK_APP_SECRET, callbackURL: "http://www.example.com/auth/facebook/callback" }, function(accessToken, refreshToken, profile, done) { User.findOrCreate(..., function(err, user) { if (err) { return done(err); } done(null, user); }); } ));
      
      



Passport.jsライブラリ自体には、いくつかの単純な認証メカニズムのみが含まれています。 それらとContext以外には何もありません。 このアーキテクチャにより、サードパーティのプログラマは、プロジェクトを煩雑にすることなく、独自の認証メカニズムを簡単に実装できます。



道徳

Strategy Patternは、コードのモジュール性と検証可能性を向上させる方法を提供します。 しかし、これは、それがどこであってもなくても使用する必要があることを意味するものではありません。 また、 不純物を使用して、実行時にオブジェクトに機能を追加すると便利です。 そして時には、古き良きアヒルのタイピングのスタイルにおける単純なポリモーフィズムで十分です。



何らかの方法で、最初にSTRATEGYを使用すると、アーキテクチャの大きなオーバーヘッドを回避しながら、コードをスケーリングできます。 これはPassport.jsで見ることができます。Passport.jsでは、このパターンを使用することで、他のプログラマーからの新しい戦略を簡単に追加できます。



All Articles