最も汎用的なパターン「完全コンストラクタ(Complete Constructor)パターン」の紹介
好きなパターンはなんですか?と聞かれたら私が真っ先に答えるのは「完全コンストラクタ(Complete Constructor)パターン」です。汎用的かつ効果的なパターンなので、多くの人に知ってもらいたくて記事を書きました。
「完全コンストラクタ(Complete Constructor)パターン」とは?
コンストラクタですべてのプロパティ(メンバ変数)を設定し終える(完全な状態)を作るパターンです。setterは作らず、プロパティがコンストラクタの実行後に変わることはありません。
簡単な例
四則演算を行うCalculatorClassをRubyで書くと次のようになります。*1プロパティをinitilizeで設定した後は一切変更していません。
class Calculator attr_reader :operand1, :operand2 def initialize(operand1:, operand2:) @operand1 = operand1; @operand2 = operand2 end def sum operand1 + operand2 end def difference operand1 - operand2 end def product operand1 * operand2 end def quotient operand1 / operand2 end end
※attr_readerはgetterメソッドのようなものをまとめて定義してくれると思ってください。詳しくはこちら
長所
- 可読性が高まる
- 単一責任原則(SRP)を守りやすい
可読性が高まる理由
完全コンストラクタに則ったクラスはその性質上、IF(インターフェース)がシンプルになりクラス内の見通しがよくなります。また、クラスを呼び出す側においても、プロパティをまとめて入力してインスタンス化し、目的のメソッドを実行するというシンプルな流れになります。そこかしこでsetterが呼ばれ、状態が変わることがないため非常に見通しがよくなります。
ccc = CompleteConstructorClass.new(x, y, z)
ccc.do
単一責任原則(SRP)を守りやすい理由
操作に必要なプロパティすべてをまとめて入力するため、多種多様な責務をクラスに持たせることが難しいです。*2また、インスタンス化後にプロパティを変更できないため、メソッド実行結果は(基本的に)同じ結果を返します。そのためメソッド実行後にインスタンスを使い捨てることが多く、使い回して多数の責務を持つような実装にはしづらくなります。一度インスタンス化してしまえば、メソッド実行結果は同じものを返すため、テストも非常に行いやすいです。
具体例: Finderパターンを完全コンストラクタで実装
Railsで構築されたあるSNSアプリで、ユーザは氏名・生年月日・性別・出生都道府県・現住都道府県のような情報を持つ。そのアプリでユーザを複雑な条件で絞り込みたいときに(Finderパターン)を使うとして、それを完全コンストラクタで実装します。
class UserFinder attr_reader :gender, :age, :today, :born_in_prefecture, :living_in_prefecture def initialize(gender: nil, age: nil, born_in_prefecture: nil, living_in_prefecture: nil) @gender = gender; @age = age; @today = Date.current @born_in_prefecture = born_in_prefecture; @living_in_prefecture = living_in_prefecture end def find query = User.all query = query.where(gender: gender) if gender query = query.where(born_in_prefecture: born_in_prefecture) if born_in_prefecture query = query.where(born_in_prefecture: living_in_prefecture) if living_in_prefecture query = query.where(birth_day: period_covered) if age return query end private def period_covered from_date = today - (age + 1).year + 1.day to_date = today - age from_date..to_date end end
このように検索の実装部分が多少複雑でも、利用時は次のとおりで「大阪生まれで今東京に住んでいる20才」を検索するということが一目瞭然になります。
result = UserFinder.new(age: 20, born_in_prefecture: "大阪", living_in_prefecture: "東京").find
Finderパターン以外にのデザインパターンとも相性がよく組み合わせて使用することでよりよい設計ができるようになります。
総括
「完全コンストラクタ(Complete Constructor)パターン」はシンプルなパターンで覚えやすいのに、汎用的かつ効果的なのでぜひ利用してください!
おまけ: デザインパターンに関する参考資料
- 作者: エリックガンマ,ラルフジョンソン,リチャードヘルム,ジョンブリシディース,Erich Gamma,Ralph Johnson,Richard Helm,John Vlissides,本位田真一,吉田和樹
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 1999/10
- メディア: 単行本
- 購入: 21人 クリック: 711回
- この商品を含むブログ (202件) を見る