Movatterモバイル変換


[0]ホーム

URL:


酒と泪とRubyとRailsと

ストラテジ(Strategy) | Ruby デザインパターン


GoFのデザインパターン(Design Pattern)のストラテジー(Strategy)のRubyコードを使った紹介記事です。
ストラテジーパターンは、たとえば5ステップの中の3ステップが異なったAとBがあり、このAとBをスイッチしたい時に使えるパターンです。

🐰ストラテジの構成

ストラテジは次の3つのオブジェクトによって構成されます。

  • コンテキスト(Context):ストラテジの利用者
  • 抽象戦略(Strategy):同じ目的をもった一連のオブジェクトを抽象化したもの
  • 具象戦略(ConcreteStrategy):具体的なアルゴリズム

ストラテジのアイデアは、コンテキストが「委譲」によってアルゴリズムを交換できるようにすることです。委譲とは、ある機能をもつオブジェクトを生成してオブジェクトに処理を依頼することです。

🍮ストラテジのメリット

  • 使用するアルゴリズムに多様性を持たせることができる
  • コンテキストと戦略を分離することでデータも分離できる
  • 継承よりもストラテジを切り替えるのが楽

😼サンプルソース1

レポートをHTML形式とプレーンテキスト形式で作成するプログラムをサンプルとしてストラテジーパターンを解説します。サンプルの概要は次のとおりです。

  • Report(コンテキスト):レポートを表す
  • Formatter(抽象戦略):レポートの出力を抽象化したクラス
  • HTMLFormatter(具象戦略1):HTMLフォーマットでレポートを出力
  • PlaneTextFormatter(具象戦略2):PlanTextフォーマットでレポートを出力

まずイメージしやすい、HTML形式で出力するHTMLFormatterクラスとPlaneTextFormatterクラス、そしてその2つのクラスのインタフェースを規定するFormatterクラスを作成します。

# レポートの出力を抽象化したクラス(抽象戦略)
classFormatter
defoutput_report(title, text)
raise'Called abstract method !!'
end
end

# HTML形式に整形して出力(具体戦略)
classHTMLFormatter< Formatter
defoutput_report(report)
puts"<span>#{report.title}</span>"
report.text.each {|line| puts"

#{line}

"
}

puts'
'
end
end

# PlaneText形式(*****で囲う)に整形して出力(具体戦略)
classPlaneTextFormatter< Formatter
defoutput_report(report)
puts"*****#{report.title} *****"
report.text.each {|line| puts(line) }
end
end

続いてレポートを表すReportクラスを作成します。このクラスにはformatterがあり、このformatterによって出力フォーマットを設定します。

# レポートを表す(コンテキスト)
classReport
attr_reader:title,:text
attr_accessor:formatter

definitialize(formatter)
@title ='report title'
@text =%w(text1 text2 text3)
@formatter = formatter
end

defoutput_report
@formatter.output_report(self)
end
end

コーディングは以上です。では結果を確認します。

report = Report.new(HTMLFormatter.new)
report.output_report
#report title
#

text1


#

text2


#

text3


#

report.formatter = PlaneTextFormatter.new
report.output_report
#***** report title *****
#text1
#text2
#text3

Reportクラス内のformatterがレポートの出力を委譲されています。
上の結果からformatterをスイッチすれば出力形式(戦略)を変更させることができるのを確認できました。

ちなみに、ここにあるFormatterクラスはインタフェースを規定するだけのクラスですので、Rubyらしく書くなら不要です。(ダック・タイピング哲学)

🏀サンプルソース2

先ほどのソースコードをProcオブジェクト(コードブロック)を使って置き換えると次のようになります。

Procオブジェクトは、コードの塊を保持するオブジェクトです。lambdaが良く使われます

classReport
attr_reader:title,:text
attr_accessor:formatter

definitialize(&formatter)
@title ='report title'
@text =%w(text1 text2 text3)
@formatter = formatter
end

defoutput_report
@formatter.call(self)
end
end

HTML_FORMATTER = lambdado|context|
puts"<span>#{context.title}</span>"
context.text.each {|line| puts"

#{line}

"
}

puts''
end

PLANE_TEXT_FORMATTER = lambdado|context|
puts"*****#{context.title} *****"
context.text.each {|line| puts(line) }
end

コーディングは以上です。では結果を確認します。

report = Report.new(&HTML_FORMATTER)
report.output_report
#report title
#

text1


#

text2


#

text3


#

report.formatter = PLANE_TEXT_FORMATTER
report.output_report
#***** report title *****
#text1
#text2
#text3

先ほどよりもRubyらしいコードで同様の結果を得ることができました。

🎉ストラテジの注意点

  • コンテキストとストラテジ間のインターフェイスがストラテジの種類の増加を妨げないようにする
  • コンテキストの変更がストラテジに影響を与えないようにする

コンテキストからストラテジへのデータの渡し方は、(1) ストラテジメソッドを呼び出すときに適切なデータを渡す
(2) コンテキストへの参照をストラテジに渡すといった方法があります。これを適切に選択してストラテジの種類を増やすことを阻害しないようにしてください。

🚌サンプルソース

🐝参考リンク

🖥 VULTRおすすめ

VULTR」はVPSサーバのサービスです。日本にリージョンがあり、最安は512MBで2.5ドル/月($0.004/時間)で借りることができます。4GBメモリでも月20ドルです。 最近はVULTRのヘビーユーザーになので、「ここ」から会員登録してもらえるとサービス開発が捗ります!

📚 おすすめの書籍

Rails/Modelバリデーションコールバック変更前後の値の確認値の保存・更新アソシエーション削除メソッドSQLの実行日付カラムの設定便利なDB関連設定読込み専用(Read Only)Concern(共通処理)クエリTipsRails/Controllerrenderレシピ集HTTPステータスシンボルIPの取得についてStrong ParametersControllerのTipsRails/ViewHAMLチートシート画像アップロードフォームS3への画像アップロードForm Objectフォームヘルパー検索可能なselectタグenum - selectタグシンプルな検索ボックス別ウィンドウ・フォームRailsいろいろi18nについてRails.cacheメール送信ロギングCapistrano3でデプロイセッション管理環境ごとのYAML設定読込xx分前の時間表記Tipsいろいろ便利ライブラリ簡単Webmock:VCRN+1対策:bullet環境変数の管理: dotenvi18nサポート: i18n-tasksLDAP:net-ldapヘッダ:secureheadersrack-mini-profileractiverecord-precountカバレッジ計測パンくずリスト+MetadataRSpecの記法自動修正アプリランキング取得Unicorn導入手順unicorn-worker-killerRSpecController SpecCapybaraとヘッドレスChromeRequest SpecAPI認証 Spec便利Tipsデザインパターン概要アブストラクトファクトリビルダファクトリメソッドアダプタコンポジットデコレータプロキシコマンドインタプリタイテレータオブザーバストラテジテンプレートメソッドRuby基礎文字列/String配列/Arrayハッシュ/Hash構造体/StructSpawn(コマンド実行)BundlerについてTipsRails 5.1へのアップデートRails 5へのアップデートrbenvバージョンアップpumaをsystemdで動かすURI.encodeとCGI.escapeURLのパラメータを変更処理時間を計測画像JPEG/PNG/GIF判定トラブルシュートNo route matches assets

[8]ページ先頭

©2009-2025 Movatter.jp