トップ «前の日記(2004-05-24) 最新 次の日記(2004-05-26)» 編集

日々の破片

著作一覧

2004-05-25

_ IT*Pro第4弾

軽いウォッチガイド

この日記の読者には何を今更感が漂う初夏の風だが、こんなもんかな。TheServerSide.comとか知らない人多そうだし。

_ DIコンテナ無しでドメイン特化DIを実現する

DIコンテナを利用せずにコントローラ(MVCのCというよりはBCEのC)が依存性注入する方法を考えてみる。
たとえば、特定の文字列や数値への依存性が既に決定しているという状態がある。
例)
interface FooDomainLogicGroup {
    // 通信相手
    void setServerName(String host);
    // 通信ポート
    void setServerPort(short port);
}
例が例によって良くないが(すべてのビジネスロジックが通信するなんてバカなことはあり得ない)、こういうものの依存性を、コントローラで解消させることを想定する。
こういうのは多分beanを使って実装する。
interface FooConfiguration {
  Strng getServerName();
  short getServerPort();
}
class Controller {
  FooConfiguration config;
  void init() {
     final String name = lookup("server");
     final short port = lookup("port");
     config = new FooConfiguration() {
       public String getServerName() {
         return name;
       }
       public short getServerPort() {
         return port;
       }
     }
   }
    ...
   void executeBean() {
     ...
     bean = createBean(...some condition...);
     bean.setConfiguration(config);
     bean.execute();
     ...
  }
}
しかし、システムがでかくなると、FooConfiguration がどんどん肥大化することになる。すると、いろいろ厄介である。
そこで構成データを分野ごとに細分することを考える。これならば、肥大化はなくなるが、その場合、beanが実装するのはsetConfiguration(FooConfiguration conf);というメソッドシグネチャではまずい。
1つの方法は、細分化したConfigurationBeanのスーパーインターフェイスを定義し、setConfiguration(SuperConfig conf);というメソッドを実装させることだ。
しかし、この場合、すべてのbeanが
void setConfiguration(SuperConfig conf) {
  if (conf instanceof ServerConfig) {
     serverName = conf.getServerName();
     ...
  } else if (conf instanceof ExtendedServerConfig) {
     extendedServerConfig = (ExtendedServerConfig)conf;
  }
  ...
}
というように、与えられたインスタンスが自分が求めるものかどうかを判定しなければならなくなる。
これは馬鹿げている。
そこで、差の吸収を呼び出し側に移動して、次のようにするのが良いだろう。
interface ServerConfigurable {
  void setConfig(ServerConfig conf);
}
interface ExtendedServerConfigurable {
  void setConfig(ExtendedServerConfigurable conf);
}
class FooBean implements ServerConfigurable, ExtendedServerConfigurable {
  void setConfig(ServerConfig conf) {
    ..
  }
  ..
}
この場合、コントローラ側でbeanの判定をすることになる。
   void executeBean() {
     ...
     bean = createBean(...some condition...);
     if (bean instanceof ServerConfigurable) {
       ((ServerConfigurable)bean).setConfig(config);
     } 
     if (bean instanceof ExtendedServerConfigurable) {
       ((ExtendedServerConfigurable)bean).setConfig(extConfig);
     }
     bean.execute();
     ...
  }
ここまで特化してしまうと、では
interface JdbcConfigurable {
  void setConnection(Connection conn);
}
class DaoBean implements JdbcConfigurable {
  ...
}
とか、なんでも良いことになってくる。instanceof判定はコントローラに集中しているから1つ実装するも2つ実装するもそれほど変わらないからだ。(場合の数が増えるとifが増えすぎて下品になるので、そのあたりはコード上の工夫は必要)
DIコンテナを利用すると、たとえばこれらは
class DaoBean {
  void setJdbcConfig(JdbcConfiguration conf) {
    connection = conf.getConnection(); // これだけならConnectionのセッタで良いわけだがあくまでも例
  }
  void setServerConfig(ServerConfig conf) {
    serverConfig = conf;
  }
  ...
}
というようになる。
差は
class DaoBean implements JdbcConfigurable, ServerConfigurable {
              ----------超えられない壁
class DaoBean {
どちらがPOJOかと言えば下だ。しかし、ドメイン特化という意味では上のほうが宣言付きなため気分的に安全度が高い(良くわからん理由だな)。また、テストのしやすさという点に関しては上も下も違いは無い(実装するメソッドは結果的には同じものになるからだ)。
もしコントローラとxConfigが密結合しても問題ないのであれば、こんな方法でもEの独立性は保つことができる。例えばこのような密結合が有り得るのはxConfigが独自に設定を読み取る能力はなく、コントローラが自分の情報でxConfigを設定しなければならないといった情況だ。たとえばServletConfigから情報を取得するような場合である。逆にInitialContextやプロパティから情報を取得できるのであればxConfigは独立したbeanとして実装できるから、コントローラと密結合させる必要は無い。もちろんTestCase内ではどちらにしてもテスト側で生成することになる。
当然、コントローラとxConfigが疎結合可能な場合には、DIコンテナを利用することでxConfigの追加や変更がコントローラと独立できるというメリットが得られる。
本日のツッコミ(全4件) [ツッコミを入れる]
_ (2004-05-25 09:15)

DIってNaHiさんがなすらぐで話してた Dependency Injection かな。<br>なにもわかってない咳は‥

_ (2004-05-25 09:15)

「オブジェクト指向(プログラミング)みたいだね」といいました。<br>素人ですみません。えへへ。

_ arton (2004-05-25 10:23)

何が素人なんだか……玄人中の玄人じゃないですか、というかクロウトってこういう漢字なのかとあらためてびっくり。

_ kdmsnr (2004-05-25 11:12)

読者層、不明ですね...。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|12|

ジェズイットを見習え