6. Factoryを利用したレイヤ間依存の疎結合化
さて前回までで表示とロジックの分離を押し進めた結果、MV(R)Pパターンに行きついた。
今回はここからさらに、Presenter、BusinessLogic、DataAccessの各レイヤの結合度合いを弱める努力をしてみたい。
前回まで、窓口クラスからデータアクセス層に属するクラスを呼ぶ際にnewを使っていた。
public void Pow(int number)
{
Number = new Number(number);
Number.Pow();
var dao = new NumberFile("pow");
dao.Save(Number);
Calculated(Number.Value);
}
この部分である。
var dao = new NumberFile("pow");
だがしかし、このように書いていたのでは差し替えが難しい。例えば、「保存先はAPIサーバー経由のDBでお願いします。あ、でも、ローカルでUnityエディタ使ってるときだけはローカルPCに保存して下さい」といった諸行無常の響きが感じられるリクエストが来た時に泣きを見る。
また、ユニットテストを行おうとしたときも、モックに差し替えるのが難しいため逐一ディスクのIOが走ってテストが遅くなるとか、MediatorのテストのはずなのになぜかDaoのテストをしているといったありがたくない効果を得てしまう。(こちらはMolesがなんとかしてくれるかもしれないが)
というわけで下記のようにFactoryを使ってdaoを呼び出すようにした。
public void Pow(int number)
{
var Number = new Number(number);
Number.Pow();
var dao = NumberDaoFactory.Create("pow");
dao.Save(Number);
ReactNum.Value = Number.Value;
}
こうすると、生成をFactory側で一括して取り扱えるため、差し替えが入っても変更が最小限で済む。現在のコードは下記のようになっているのだが、
public class NumberDaoFactory
{
public static INumberDao Create(string key)
{
return new NumberFile(key);
}
}
たとえば次のように書き換えれば上述の愉快リクエストもさばくことができるはずだ。
public class NumberDaoFactory
{
public static INumberDao Create(string key)
{
if (UNITTEST)
return Mock(key);
if (ENVIRONMENT == "local")
return new NumberFile(key);
} else {
return new NumberApi(key);
}
}
}
また、Presenter側も同じく、Mediatorを呼び出すところをFactory経由にした。こちらは「とりあえずロジック部分はスタブで」が簡単にできるように、という意味合いが大きい。
private void Start()
{
// Modelの値の保持
NumberMediator = MediatorFactory.Create<NumberMediator>();
尚、このあたりのテクニックについてはC#実践開発手法を参考にした。
どこまでやるか
さていいことづくめのように思えるこの手法なのだが、副作用もある。やればやるほどinterfaceが大量に必要になるのだ。
これはこれで嫌なものなので、今回は各レイヤを接続する箇所に限定している。つまりPresenterがMediatorを呼ぶ個所と、BusinessLogicに属するクラスからDaoを呼ぶときである。
実際のコード
今回利用したサンプルはGithubの下記URLにアップしている。
https://github.com/nakatatsu/unity-sample
残る課題
今回課題と考えていた点はひととおり試すことができたように思う。そこで最後にふりかえりを兼ねて経緯をまとめたい。