前回は,クラステンプレート AnimalTemplate を導入することで,IAnimal インタフェースと Dog/Cat クラスの継承関係を断ちました.
今回は,利用側である main.d ファイルと具象クラス Dog/Cat の依存関係を断つために,シンプルなファクトリクラスを導入します.
main.d ファイルが Dog/Cat クラスに依存しているのは,( AnimalTemplate を介して) Dog/Cat クラスのコンストラクタを呼び出しているからです.
そのせいで,せっかく IAnimal インタフェースを介した抽象化をしているのに,具象クラスに依存してしまっています.
また,コンストラクタの呼び出しが色々な場所で行われることで,同じコードが重複したり,インスタンスの管理が難しくなります.
それでは,このような問題を回避するために,ファクトリクラスを導入して main 関数から Dog/Cat クラスへの依存を断ちましょう.
まず,元のコードを示します.
import std.stdio; // ++ animal.d interface IAnimal { void bark(); } class AnimalTemplate(T) : IAnimal { private T t; this() { t = new T; } void bark() { t.bark(); } } // ++ dog.d class Dog { void bark() { writefln("wan!wan!"); } } // ++ cat.d class Cat { void bark() { writefln("nyan!nyan!"); } } // ++ main.d //import animal, dog, cat; void main() { IAnimal animal = new AnimalTemplate!(Dog); animal.bark(); animal = new AnimalTemplate!(Cat); animal.bark(); }
次に,ファクトリクラスを導入して依存関係を断ったコードを示します.
import std.stdio; // ++ animal.d interface IAnimal { void bark(); } class AnimalTemplate(T) : IAnimal { private T t; this() { t = new T; } void bark() { t.bark(); } } // ++ dog.d class Dog { void bark() { writefln("wan!wan!"); } } // ++ cat.d class Cat { void bark() { writefln("nyan!nyan!"); } } // ++ animalfactory.d //import animal, dog, cat; class AnimalFactory { static IAnimal create(uint code) { switch (code) { case 0: return new AnimalTemplate!(Dog); case 1: return new AnimalTemplate!(Cat); } } } // ++ main.d //import animal, animalfactory; void main() { IAnimal animal = AnimalFactory.create(0); animal.bark(); animal = AnimalFactory.create(1); animal.bark(); }
とてもシンプルなファクトリクラス AnimalFactory を追加しました.
main.d ファイルの中では,このファクトリクラスを介してインスタンスを受け取っています.
これで,利用側の main.d ファイルが Dog/Cat クラスに直接依存することを避けることができました.
さて,次のエントリーでは,今追加したファクトリクラスの Dog/Cat クラスへの依存を断ってみます.
果たして,そんなことができるのでしょうか.