[書評・読書メモ] 「アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座」でデザインパターンの基本5パターンを学ぶ

読書メモと写経。

「オブジェクト指向言語でよく使われるデザインパターンのうち基本5パターンを覚えなさい。」とのこと。

  1. ステート/ストラテジー (State/Strategy)
  2. ファクトリーメソッド (Factory Method)
  3. アダプター (Adapter)
  4. コンポジット (Composite)
  5. テンプレートメソッド (Template Method)

実際は6つ。

Contents

Strategy

ストラテジーパターンは、戦略(ストラテジー)により振る舞いを切り替えます。この切り替えには継承を利用することで、振る舞いの異なるオブジェクトを同じように利用できるようにします。呼び出し側のプログラムを変更することなく、呼び出される側のオブジェクトを切り替えることで、動作を切り替えることができます。

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.980-982). 株式会社 翔泳社. Kindle 版.

実際には、複雑な業務手順を入れ替えたりするときに、このストラテジーパターンは使われます。例えば、データを画面に表示させる手順と、プリンタに印刷させる手順を入れ替えるような場合です。

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.1013-1015). 株式会社 翔泳社. Kindle 版.

参考資料

State

オブジェクトの振る舞いに注目したストラテジーパターンとは異なり、ステートパターンは状態を表すためにオブジェクトを利用します。

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.1019-1020). 株式会社 翔泳社. Kindle 版.

ここで重要なのは同じ社員であっても、役職という状態(ステート)を変えるだけでそれに対応して給料計算という振る舞いが変えられるということです。ステートパターンは状態の変化とそれに伴う変化をオブジェクトとして捉えているところが重要です。

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.1046-1048). 株式会社 翔泳社. Kindle 版.

参考資料

Factory Method

ステート/ストラテジーパターンでは、使用するクラスを切り替えることで振る舞いや状態を変えることができるように設計しました。ファクトリーメソッドパターンは使用するファクトリーを切り替えることで生成するインスタンスを切り替えます。

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.1050-1052). 株式会社 翔泳社. Kindle 版.

shain_factory.rb
# ShainFactory class from lesson 4.4
class ShainFactory
  def create(type, kihonkyu)
    shain = nil

    if type == 'Tanto'
      shain = Tanto.new(kihonkyu)
    elsif type == 'Shunin'
      shain = Shunin.new(kihonkyu)
    end

    shain
  end
end
shain_factory.rb
# ShainFactory class, meta programing version from lesson 4.4
class ShainFactory
  def create(type, kihonkyu)
    eval "#{type}.new(#{kihonkyu})", binding, __FILE__, __LINE__
  end
end

参考資料

Adapter

アダプターパターンは既に存在しているコードと新しく作られるコードをつなぎ合わせて再利用するためのパターンです。

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.1070-1071). 株式会社 翔泳社. Kindle 版.

まとめると、Ruby では Adapter クラスを作らずとも同等の機能を実現できる手法もある、という事らしい。

  1. 変更の頻度が高くないと予想 -> 直接クラスに変更を加える。
  2. とりあえずの実装 -> モンキーパッチを当てて挙動を見る。
  3. 今後の変更が予測できない -> 安全策で委譲(has a 関係)を利用したアダプターパターンを使う。

以下などを基準にどんな手法を使うか判断する。

  • カプセル化が必要かどうか
  • 変更の頻度が高いか低いか
  • 実装についてのコストがどれだけ違うか

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.1134-1139). 株式会社 翔泳社. Kindle 版.

以下のコードを用意、実行。

[1] pry(main)> require_relative './hakenmoto/hakenshain'
=> true
[2] pry(main)> hakenshain = Hakenshain.new
=> #<hakenshain:0x00007f95f29145f8>
[3] pry(main)> hakenshain.kiritsu
派遣社員は元気に立ち上がりました。
=> nil

直接クラスを変更

[1] pry(main)> require_relative './hakenmoto/hakenshain'
=> true
[2] pry(main)> hakenshain = Hakenshain.new
=> #<hakenshain:0x00007f95f29145f8>
[3] pry(main)> hakenshain.standup
派遣社員は元気に立ち上がりました。
=> nil

オープンクラス(モンキーパッチ)

既存のクラスに対して、メソッドを追加したり書き換えたりすることをオープンクラスと呼ぶ。

[1] pry(main)> require_relative './hakenmoto/hakenyobidashi'
=> true
[2] pry(main)> hakenshain = Hakenshain.new
=> #<hakenshain:0x00007fff35a27da8>
[3] pry(main)> hakenshain.standup
派遣社員は元気に立ち上がりました。
=> nil

委譲(has a 関係)を利用したアダプターパターン

GoF Rubyデザインパターンでは設計原則として、継承よりも委譲のほうが好ましいと何度も書かれています。 なぜなら、継承はクラス同士の結合度が上がってしまうからです。

Rubyデザインパターン 2日目 : Strategy – Qiita

継承(is a 関係)

デメリットは、全てのメソッドを継承していること。
これも4.5.1と同じくカプセル化が不十分。
クラスとクラスの関係が強すぎるため、影響範囲が広くなり変更に弱くなってしまう。

[1] pry(main)> require_relative './ukeireshain'
=> true
[2] pry(main)> shain = Ukeireshain.new
=> #<ukeireshain:0x00007fd2f4159018>
[3] pry(main)> shain.standup
派遣社員は元気に立ち上がりました。
=> nil

委譲(has a 関係)

本来そのクラスが果たすべき役割を他のクラスに任せるようなやり方を「委譲」という。
関係が密接になりすぎることがないので、変更の影響は受けにくくなる。
デメリットは、継承のようにクラスの機能をそのまま引き継げないこと。

[1] pry(main)> require_relative './tsuyakushain'
=> true
[2] pry(main)> shain = Tsuyakushain.new
=> #<tsuyakushain:0x00007f9abf0c02b8 @gyoumu=#<gyoumu:0x00007f9abf0c0290>, @yakushoku=#<yakushoku:0x00007f9abf0c0268>>
[3] pry(main)> shain.standup
派遣社員は元気に立ち上がりました。
=> nil
[4] pry(main)> shain.calculate_salary(100)
=> 100

参考資料

Composite

同じような構造を持つクラスが階層を作るような場合が、このパターンの出番です。

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.1187). 株式会社 翔泳社. Kindle 版.

要追加調査。

参考資料

Template Method

テンプレートメソッドのテンプレートとは、いろんな文書のひな形をそう呼ぶように、いろいろなクラスで共通して使う部分をあらかじめ作っておくことです。

長瀬 嘉秀; 小林 慎治; 大崎 瑶. アジャイル時代のオブジェクト脳のつくり方 Rubyで学ぶ究極の基礎講座 (Kindle の位置No.1204-1206). 株式会社 翔泳社. Kindle 版.

参考資料

所感

他の書籍も読みたい。

補遺

6章は、Rails。

7章は、関数型プログラミング。

7章に関して調べた追加情報。