...ing logging 4.0

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

クラス間依存関係の除去 第3回 - ファクトリクラスの導入によるインスタンス生成処理の分離

前回は,クラステンプレート 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 クラスへの依存を断ってみます.
果たして,そんなことができるのでしょうか.