new によるインスタンス化は避けるべきか?
アプリを設計していると、実装はオブジェクト指向パラダイムな言語で書くことが多いので、オブジェクト指向プログラミングについて思い出したり勉強し直したりすることが多々ある。
今回はドメインエンティティのインスタンスをプレゼンテーション層で作成する時に、条件反射的に new
キーワードによるインスタンス化を回避して Factory や Repository による抽象化を行おうとして、これは過度な抽象化なんじゃないか?と疑問を抱いたので調べたり考えたりした。そのメモ。
new によるインスタンス化
new によるインスタンスは避けるべきだと言われている。 new によるインスタンス化はインスタンス化したいオブジェクトの具象クラスに依存しなければならず、オブジェクト指向の大原則、具象ではなく抽象に依存するという原則を侵害することになるからだ。
抽象化する理由
しかし、何でもかんでも具象クラスのコンストラクタを直接使用したインスタンス化がだめだというわけではない。 たとえば String クラスや Date クラスに対する依存をやめるべきか?そんなわけない。 String は CharSeaquence を実装しているが、いちいち文字列を使用する箇所を全て CharSeaquence 型にするのは現実的だとは思わない。
これはそもそもなぜ抽象に依存すべきなのかを考えれば明確である。 抽象に依存するべきである理由はいくつかあるが、 (1) プログラムは変わりやすいものよりも変わりにくいものに依存するべきだから (2) テストをするときにモックアップしやすいから (3) オブジェクトの利用者は利用するオブジェクトの実装の詳細を知るべきではないから といったような理由が多い気がする。
抽象化しなくても良いこともある
今回はアプリのドメインモデルを成すエンティティ(ドメインエンティティ)のインスタンスの生成を抽象化すべきか?というのが問題である。 結論からいえば、単純な値オブジェクトのようなエンティティであれば、抽象化する必要はないと思う。 理由は単純で、そもそもドメインエンティティは変更されにくいはずである。ドメインエンティティに対する変更は、すなわちそのアプリケーションの仕様変更であると言える。そのような仕様変更があるのだとすれば、仮に抽象化していたところでインタフェースに変更が加えられ、大規模な変更が生じることに違いはないと思う。また、単純な振る舞いしか持たないのであればテストする際にモックアップする必要もないし、実装が複数存在することもない。
まとめ
抽象化する必要のないようなクラスであれば、 new しても良い。そもそも抽象化していないクラスを Factory にしたところで Factory#create()
メソッドの戻り値はその具象クラスになってしまうので、何の意味もない。
Factory や Repository を使うべきか?という問いの前に、そのクラスは抽象化すべきか?を考えれば良さそう。
もしその答えが No ならば、 Factory や Repository を使うべきかの答えも No である。