Ruby によるデザインパターン 第4章の Strategy を JavaScript で写経
- 作者: Russ Olsen,ラス・オルセン,小林健一,菅野裕,吉野雅人,山岸夢人,小島努
- 出版社/メーカー: ピアソン桐原
- 発売日: 2009/04/01
- メディア: 単行本
- 購入: 13人 クリック: 220回
- この商品を含むブログ (66件) を見る
レポート出力のところとかはしょっています。
ストラテジオブジェクトのメソッド呼出時に、ストラテジが必要とするすべてを引数として渡す
var Report = function () { this.initialize.apply(this, arguments) }; var htmlFormatter = function () {}; var xmlFormatter = function () {}; Report.prototype = { initialize: function(formatter) { this.title = 'タイトル'; this.description = '説明'; this.formatter = formatter; }, output_report: function() { this.formatter.output_report(this.title, this.description); } } htmlFormatter.prototype = { output_report: function(title, description) { console.log('これは HTML の出力ですよ:' + title + ':' + description); } } xmlFormatter.prototype = { output_report: function(title, description) { console.log('これは XML の出力ですよ:' + title + ':' + description); } } var report = new Report(new htmlFormatter); report.output_report(); // これは HTML の出力ですよ:タイトル:説明
切り替えが簡単
var report = new Report(new htmlFormatter); report.output_report(); // これは HTML の出力ですよ:タイトル:説明 report.formatter = new xmlFormatter; report.output_report(); // これは XML の出力ですよ:タイトル:説明
ストラテジへと渡されたコンテキスト自身の参照を使って、ストラテジがコンテキストからデータを引き出す
コンテキストとストラテジに引き渡すこのテクニックはデータの流れを単純にする一方、
コンテキストとストラテジ間の結合度を上げてしまうことにもなります。
このため、コンテキストとストラテジがお互いにもつれ合ってしまう危険があります。
var Report = function () { this.initialize.apply(this, arguments) }; var htmlFormatter = function () {}; var xmlFormatter = function () {}; Report.prototype = { initialize: function(formatter) { this.title = 'タイトル'; this.description = '説明'; this.formatter = formatter; }, output_report: function() { this.formatter.output_report(this); } } htmlFormatter.prototype = { output_report: function(context) { console.log('これは HTML の出力ですよ:' + context.title + ':' + context.description); } } xmlFormatter.prototype = { output_report: function(context) { console.log('これは XML の出力ですよ:' + context.title + ':' + context.description); } } var report = new Report(new xmlFormatter); report.output_report(); // これは XML の出力ですよ:タイトル:説明
単にコードブロックで渡す - Ruby
一体なぜ、わざわざ Proc ベースのストラテジにするのでしょうか?
理由の1つは、ストラテジのためにあえてクラスを作る必要がなくなり、
Proc オブジェクトにコードをただ包むだけにできるからです。
このことが意味するのは、クラスベースのストラテジなんか忘れてしまっていいということでしょうか?
実際にはそうでありません。コードブロックベースのストラテジは、そのインターフェースが単純で、
1つのメソッドで事足りるようなときにのみ有効に働きます。つまるところ Proc オブジェクトに対して
呼べるメソッドは call しかないのです。ストラテジにもっとやることがあるのなら、
そのときこそクラスベースのやり方で作ることになります。
しかしシンプルなストラテジで要件に合うのなら、コードブロックを使ったやり方を使うべきです。
class Report attr_reader :title, :description attr_accessor :formatter def initialize(&formatter) @title = 'タイトル' @description = '説明' @formatter = formatter end def output_report @formatter.call(self) end end HTML_FORMATTER = lambda do | context | puts("これは HTML の出力ですよ:#{context.title}:#{context.description}") end XML_FORMATTER = lambda do | context | puts("これは XML の出力ですよ:#{context.title}:#{context.description}") end report = Report.new &HTML_FORMATTER report.output_report
単にコードブロック(closure)で渡す - JavaScript
Ruby の Proc オブジェクト自体をよくわかってないので、これでいいのかはよくわからない。
var Report = function () { this.initialize.apply(this, arguments) }; var htmlFormatter; var xmlFormatter; Report.prototype = { initialize: function(formatter) { this.title = 'タイトル'; this.description = '説明'; this.formatter = formatter; }, output_report: function() { this.formatter(this); } } htmlFormatter = function(context) { return console.log('これは HTML の出力ですよ:' + context.title + ':' + context.description); } xmlFormatter = function(context) { return console.log('これは XML の出力ですよ:' + context.title + ':' + context.description); } var report = new Report(htmlFormatter); report.output_report(); // これは HTML の出力ですよ:タイトル:説明