本日のカクテルはDIコンテナです。
こちらのカクテルはオブジェクト指向をベースとしてますので、苦手な方は無理なさらずに。
レシピはオブジェクト指向3/4にStrategyパターンを1/4をステア。マティニのようなショートカクテルに仕上がります。
Java界隈では2004年頃からにわかに熱を帯びていたDIコンテナ(当時はIoCコンテナと呼ばれていた)ですが、一体何者なんだろう?
その掴みどころのなさは、そのメリットがどうにも抽象的に語られるからではないでしょうか。
そのメリットは「オブジェクト間の疎結合」などと言われますが、これはオブジェクト指向を学んだ技術者でも
いまいちイメージしにくいメリットです。いや、メリットはわかったとしてもどうやって?そんなものフレームワークになりえるの?
と疑問は尽きない、そんな話だと思うのですね。この胡散臭さが敬遠されているのではないでしょうか。
今回はソースコードを見ながらDIへの進化の軌跡をたどってみましょう。
古典的なやり方からStrategyパターンへ
if (flag == 0) {
System.out.println("flagが0のときの処理");
} else if (flag == 1) {
System.out.println("flagが1のときの処理");
} else if (flag == 2) {
System.out.println("flagが2のときの処理");
}
flagの値でif文を作っている、古典的な条件分岐です。
このコードではflagは0~2ですが、新しく3を追加するとこのif文を増やさねばなりません。
そして、このようなif文がソースコードのあちこちにあるとすると…
つまり、修正がある場合や拡張がある場合には、これらのif文を探して全ての箇所に手を入れなければなりません。
そこでオブジェクト指向のポリモーフィズム(多態)を使ってこれらをまとめる手法が編み出されました。
interface Strategy {
void hoge();
void piyo();
}
class Strategy0 implements Strategy {
public void hoge() {
System.out.println("flagが0のときのhoge()");
}
public void piyo() {
System.out.println("flagが0のときのpiyo()");
}
}
void test(Strategy strategy) {
// if文での分岐の変わりにポリモーフィズムを使う!
strategy.hoge();
// 複数の大きなif文がそれぞれただのメソッド呼び出しになる
strategy.piyo();
}
例示のコードではStrategyというinterfaceを宣言し、
その実装クラスStrategy0を作りました。
そしてメソッドtest()では、Strategyのメソッドを呼び出すだけになります。
if文の代わりにポリモーフィズムで分岐するのです。
これがGoFデザインパターンのひとつStrategyパターンです。
このtestメソッドの呼び出し元では
test(new Strategy0());
というようにStrategyの実装Strategy0のインスタンスをnewして渡してやります。
ここで渡す具象型を変えてやると中でポリモーフィズムが働き、if文での分岐のように処理が切り替えられるのです。
そして、この実装を追加するだけで容易にバリエーションを増やすことが出来ます。
これまではif文のelse-ifが延々と増えていたというのに!
StrategyパターンからDIへ
このStrategyパターン、GoFデザインパターンの中でも非常に使い勝手のよいパターンです。
Strategyというinterfaceを呼び出す際には具象クラスを知る必要はありません。
実際のインスタンスの型の違いがそのままポリモーフィズムによって挙動の違いとなって現れるのです。
でも、どこかで具象型のインスタンスを生成しなければなりません。
インスタンス生成の場ではさすがに具象型を知らないわけには行かないのです。
では、何らかのフレームワークが設定ファイルを元に実行時に動的に具象型のインスタンスを生成して
必要なフィールドに設定してくれるとしたらどうでしょう?
設定ファイルを書き換えるだけで、再コンパイルなしにポリモーフィズムで挙動が切り替えられるのです!
public class DITest {
/** フィールド。DIコンテナによって設定される */
private Strategy strategy;
/** setter */
public void setStragety(Strategy strategy) {
this.strategy = strategy;
}
void test() {
// if文での分岐の変わりにポリモーフィズムを使う!
this.strategy.hoge();
// 複数の大きなif文がそれぞれただのメソッド呼び出しになる
this.strategy.piyo();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="diTest" class="DITest" >
<property name="strategy" >
<ref bean="strategy_0" />
</property>
</bean>
<bean id="strategy_0" class="Strategy0" />
</beans>
これこそがDIコンテナのしてくれることなのです。
DIコンテナをうまく活用するとモックを使って並列な開発が容易になります。
また、実運用時でも設定ファイルの書き換えで多様な実装に切り替えることが出来ます。
DBアクセス部分をうまく切り分けておくと、後になってからDBの種類の変更することまで可能になります。
(もちろん、新たなDBとやりとりする部分は書き起こさないといけませんが)
どうでしょうか?なんとなく、このカクテルの味わいがご理解いただけたでしょうか?
DIコンテナの今
現在、主要なDIコンテナは
の2台巨頭といったところです。
.NET用のS2Container.NETといったものも出てきていますね。
また、このDIコンテナの考え方はJavaEEの標準にとりこまれEJB3.0としてリリースされています。
いずれにせよ、このDIコンテナの有用性はこの数年の間に実証されてきました。
今後も生き延びていく重要な設計技法となるのではないでしょうか。
投稿日時 : 2007年8月3日 0:30