目次
この回では、AngulerJSを少し本格的に使用して会員管理システムを構築する。
ここで用いるAngulerJSの機能および関連項目は以下のようなものである。
多くのデータベースアプリケーションが取り入れているデザインパターンの一つ。
それぞれの単位が責任を分担することで、見通しの良いすっきりとした構造のアプリケーションを構築することができる。
会員管理システムのMVCの構成は以下のようになる。
依存性注入とは(Wikipediaによると)マーティン・ファウラーによる造語で、あるコンポーネントAの中で別なコンポーネントBを使用する際、コンポーネントBをコンポーネントAの中で内部的に生成するのではなく、外部のインターフェイスなどを使って間接的に導入(これを注入という)することにより、コンポーネント間の依存関係を薄くし、単体テストを実施しやすくする技術である(とのこと)。
と言われても、何を言っているのかよくわからないかもしれないが、私の解釈によると次のようなことである。
例を挙げて説明する。
会員リストを作成するクラスMemberListのmakeList()メソッドの中で、会員の住所から郵便番号を得るZipCodeManagerというクラスを使っているとしよう。
つまり、
var MemberList=function(){
this.members=[];
this.prototype.makeList=function(){
var zcm=new ZipCodeManager(); // ←ココ
for(var i=0;i<this.members.length;i++)){
int z=zcm.getZipCode(this.members[i]); // 会員this.members[i]の郵便番号を得るはず・・・
// ...
}
}
}
問題となるのは「←ココ」と示した部分である。ここでは、newで新しいオブジェクトを生成して使っている。
ここでもし、ZipCodeManagerクラスを作っている人がなかなか開発が進まず、MemberListクラスをテストするときに間に合わなかったとしよう。このような場合は、MemberList#makeList()のテストを行うことができない。なぜなら、ZipCodeManagerのインスタンスを生成できないからである。
しかし、プログラムコードが以下のようになっていたとしよう。
var MemberList=function(){
this.members=[];
this.prototype.makeList=function(ZipCodeManager zcm){
for(var i=0;i<this.members.length;i++)){
int z=zcm.getZipCode(this.members[i]); // 会員this.members[i]の郵便番号を得るはず・・・
// ...
}
}
}
このコードでは、makeList()を呼び出すとき引数としてZipCodeManagerのインスタンスを渡している。
この場合でもやはりZipCodeManagerがなければ関数を実行することはできないわけであるが、外部からインスタンスを渡してくるということは、内部で生成するよりは依存関係が薄くなっている。
この場合、ZipCodeManagerの代わりをする別なオブジェクト(このようなオブジェクトをモックという)を引数として渡してあげれば、makeList()関数のテストを実施することが可能となる。
このように、外部からオブジェクトを入れてあげるような形を、オブジェクトの注入(Inject)と呼ぶ。またそれにより、依存性を低減することを依存性注入(DI)と呼ぶ(ということらしい)。
個人的には、ZipCodeManagerのモックのクラスを準備してリンクすれば最初のコードでもmakeList()関数のテストは可能になると思うのだが、依存性としてはどちらが低いかという後者の方が低くなっているのだとう。
DIの考え方は、コンポーネント間の依存性をできるだけ低く抑えることで、テストの実施を容易にしてソフトウェアの信頼性と保守性を向上させようということを狙っている。
AngularJSにおけるDIとは、あるモジュールの中のコントローラやサービスなどの中で、別なコントローラやサービスを使用するための手法を言う。
一般的なクラスの設計をする際、あるクラスAから別なクラスBのメソッドを呼び出す場合、クラスAはクラスBを知っている必要がある。この場合、クラスAの中にクラスBのインスタンスを保持しておくことで、これを実現できる。
しかし、この方法は2つのクラスの依存性を高めていることになり、先の依存性の低減という観点から見ればあまり良い方法ではない。
そこでAngularJSでは、各コントローラやサービス内の関数の引数で別なコントローラやサービスの名称を列挙することで、そのコントローラやサービスを利用可能となる。