元のコードは,Dog クラスと Cat クラスが IAnimal インタフェースを継承しています.
継承関係は非常に強い依存関係であるため,設計変更が難しくなりやすいです.
そこで,より弱い依存関係を目指して,テンプレートを使ってこの親子関係をなくしてみましょう.
まず,元のコードを示します.
import std.stdio; // ++ animal.d interface IAnimal { void bark(); } // ++ dog.d //import animal; class Dog : IAnimal { void bark() { writefln("wan!wan!"); } } // ++ cat.d //import animal; class Cat : IAnimal { void bark() { writefln("nyan!nyan!"); } } // ++ main.d //import animal, dog, cat; void main() { IAnimal animal = new Dog; animal.bark(); animal = new 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!"); } } // ++ main.d //import animal, dog, cat; void main() { IAnimal animal = new AnimalTemplate!(Dog); animal.bark(); animal = new AnimalTemplate!(Cat); animal.bark(); }
AnimalTemplate クラステンプレートが増えました.
これによって,Dog/Cat クラスと IAnimal インタフェースの間にある継承関係がなくなりました.
そのため,dog.d/cat.d ファイルから,animal.d ファイルの import がなくなっています.
追加した AnimalTemplate は,インスタンス化するときにテンプレートパラメータとして与えられたクラス(ここでは Dog/Cat)のインスタンスを内部で生成し,自身への bark 関数の呼び出しを,内部のインスタンスに委譲しています.
そして,AnimalTemplate が IAnimal を継承していることによって,IAnimal インタフェースを介した Dog/Cat クラスのポリモーフィズム的な振る舞いが実現できています.
ところで, main.d ファイルの中で,AnimalTemplate クラステンプレートを介し, Dog/Cat クラスのコンストラクタを呼び出しています.
つまり,利用側の main.d と具象クラス Dog/Cat クラスの依存関係が強くなっています.
では,次のエントリーでは,この依存関係を除去してみます.