今日の役に立たない一言 - Today’s Trifle! -

古い記事ではさまざまなテーマを書いていますが、2007年以降はプログラミング関連の話がほとんどです。

中心的クラスへの依存を避けよう

とあるプログラムの修正をやってる。このプログラムでは、メインになってるクラスのインスタンスを、staticメソッドで取得できるようになってる。メインのインスタンスだから、設定やログの役割を持ったインスタンスを持っていて、他のオブジェクトが設定やログにアクセスしたいときに、一旦メインのインスタンスを static メソッドで取得している。

class Main {
    private Main main;
    private Config config;
    private Log log;
    public Config getConfig() {
        return config;
    }
    public Log getLog() {
        return log;
    }
    public static Main getMain() {
        return main;
    }
       :
}

class Someone {
    void somemethod() {
        Main main = Main.getMain();
        Config config = main.getConfig();
        int v = config.getValue("somekey");
            :
    }
}

これって、よくあるパターンなんじゃないかと思う。でも、オブジェクトの依存関係からすると、あまり好ましくない。上記のコードの場合、Someone クラスは Config を使いたいだけなのに、Main には直接的に、Log には間接的に依存してしまっている。
この場合、Someone をコンパイルしようとしたり、テストしようとすると、Main や Log が必要になる。実質的には何も依存していないのに。
一般的なアプリケーションを考える場合、Main はあらゆるクラスに依存しているのがほとんどではなかろうか。つまり、Main に依存している限り、Someone は無意味にあらゆるクラスに間接的に依存していることになる。
設計の良し悪しを計るひとつの重要な基準として「結合度と凝集度」があるが、その観点で見た場合には決して良いとは言えない。無意味な結合が存在しているから。
例えば上記のコードの場合、Someone から Main への無意味な依存をなくしてしまった方が良い。方法としては、Someone の Config を必要とするメソッドには、引数で Config を渡してやるのが適切だろう。多くのメソッドで Config を必要とする場合は、setter を用意するのがいいかもしれない。Config を Singleton にする方法もあるが、その場合は Config のインスタンスがシステムで唯一であることを保証する必要がある。

class Someone {
    void somemethod(Config config) {
        int v = config.getValue("somekey");
            :
    }
}

もしくは、Someone を利用するクラスが Config から必要な設定を取り出したうえでメソッドを呼ぶようにすれば、Config への依存もなくすことができる。