...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

クラス間依存関係の除去 第2回 - テンプレートを用いた継承関係の除去

元のコードは,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 クラスの依存関係が強くなっています.
では,次のエントリーでは,この依存関係を除去してみます.