|
|
特集
.NET開発者のためのDI&AOP入門(前編)
Seasar.NETでDIを始めよう
株式会社アイビス 杉本 和也
2007/12/10 |
|
|
●2-2. DIの実践
ここではWindowsアプリケーションのサンプルでDIを実践してみよう。Windowsアプリケーションのプロジェクトを作成すると、「Form1」というクラス(Windowsフォーム)が作成されるので、下の画面のようにコントロールを配置しよう。
これから作成するサンプルは、社員コードを入力して社員検索ボタンをクリックすると社員名が表示されるという簡単なものだ。
|
サンプル・アプリケーションのWindowsフォームのデザイン |
配置するコントロールとそのプロパティを下表に記す。 |
コントロール |
プロパティ名 |
値 |
Label |
(Name) |
empCodeLabel |
Text |
社員コードを入力してください |
Label |
(Name) |
empNameLabel |
Text |
検索結果:社員名を表示します |
TextBox |
(Name) |
empCodeTextBox |
TextBox |
(Name) |
empNameTextBox |
ReadOnly |
True |
Button |
(Name) |
searchButton |
Text |
社員検索 |
|
これから作成するクラスやインターフェイスを下の図に示す。
|
サンプル・アプリケーションのクラスやインターフェイス |
-
Form1クラスにIEmployeeLogic型のフィールドEmpLogicを作成する。そこにIEmployeeLogic実装クラス(=EmployeeLogicクラス)のインスタンスがDIされ、Form1クラスからEmployeeLogicクラスの機能を利用することができるようになる。
-
同じようにEmployeeLogicクラスにIEmployeeDao型のフィールドEmpDaoを作成する。そこにIEmployeeDao実装クラス(=EmployeeDaoクラス)のインスタンスがDIされ、EmployeeLogicクラスからEmployeeDaoクラスの機能を利用することができるようになる。
それでは上の図のインターフェイスとクラスを作成しよう。以下にそのすべてのソース・ファイルの内容を掲載する。
namespace QuillSample
{
public interface IEmployeeDao
{
/// <summary>
/// 社員コードから社員名を取得する
/// </summary>
/// <param name="empNo">社員コード</param>
/// <returns>社員名</returns>
string GetEmpName(int empNo);
}
} |
|
IEmployeeDaoインターフェイスのソース・コード(IEmployeeDao.cs) |
namespace QuillSample
{
public class EmployeeDao : IEmployeeDao
{
public string GetEmpName(int empNo)
{
// 本来はデータベースなどから取得するがDIが目的なので
// パラメータの社員コードにかかわらず「山田太郎」固定で返す
return "山田太郎";
}
}
} |
|
EmployeeDaoクラスのソース・コード(EmployeeDao.cs) |
namespace QuillSample
{
public interface IEmployeeLogic
{
/// <summary>
/// 社員コードから社員名を敬称付きで取得する
/// </summary>
/// <param name="empNo">社員コード</param>
/// <returns>敬称付きの社員名</returns>
string GetEmpNameWithTitle(int empNo);
}
} |
|
IEmployeeLogicインターフェイスのソース・コード(IEmployeeLogic.cs) |
namespace QuillSample
{
public class EmployeeLogic : IEmployeeLogic
{
public IEmployeeDao EmpDao;
public string GetEmpNameWithTitle(int empNo)
{
string empName = EmpDao.GetEmpName(empNo) + "さん";
return empName;
}
}
}
|
|
EmployeeLogicクラスのソース・コード(EmployeeLogic.cs) |
using System;
using System.Windows.Forms;
namespace QuillSample
{
public partial class Form1 : Form
{
public IEmployeeLogic EmpLogic;
public Form1()
{
InitializeComponent();
}
// searchButtonのClickイベントに割り当てる
private void searchButton_Click(object sender, EventArgs e)
{
// DIが目的なので入力チェックは省略する
int empNo = int.Parse(empCodeTextBox.Text);
// 社員コードから敬称付きの社員名を取得する
string empName = EmpLogic.GetEmpNameWithTitle(empNo);
// 敬称付きの社員名をTextBoxに表示する
empNameTextBox.Text = empName;
}
}
} |
|
Form1クラスのソース・コード(Form1.cs) |
以上のソース・ファイルを実装すると、[ソリューション エクスプローラ]の内容は次のようになる。
|
サンプル・アプリケーションの[ソリューション エクスプローラ]の内容 |
これでロジック部分は完成したが、このまま実行して社員検索ボタンをクリックしてもNullReferenceException例外が発生して動作しない。EmpLogicフィールドがnullのままだからである。
ここでDIコンテナであるQuillの出番である。Quillでは、インターフェイスにImplementation属性(Seasar.Quill.Attrs名前空間)を設定して、そこでDIすべき実装クラスを指定する。
それではIEmployeeDaoインターフェイスとIEmployeeLogicインターフェイスにImplementation属性を設定してみよう。ちなみにフィールドはprotectedスコープ以上にする必要がある。
using Seasar.Quill.Attrs;
namespace QuillSample
{
[Implementation(typeof(EmployeeDao))]
public interface IEmployeeDao
{
……省略……
|
|
IEmployeeDaoインターフェイスへのImplementation属性の指定(IEmployeeDao.cs) |
using Seasar.Quill.Attrs;
namespace QuillSample
{
[Implementation(typeof(EmployeeLogic))]
public interface IEmployeeLogic
{
……省略…… |
|
IEmployeeLogicインターフェイスへのImplementation属性の指定(IEmployeeLogic.cs) |
Implementation属性でDIすべき実装クラスを指定すれば、後はQuillInjectorクラス(Seasar.Quill名前空間)のInjectメソッドに、DIを行いたいオブジェクトを渡すだけである。Injectメソッドを呼び出すには、QuillInjectorクラスのオブジェクトが必要だが、これはQuillInjectorクラスの静的メソッドGetInstanceで取得できる。
今回の場合はForm1クラスのコンストラクタで、Injectメソッドを呼び出して、ここでDIを行いたいオブジェクトであるForm1オブジェクト(this)をDIしてみる。QuillによりEmpLogicフィールドに実装クラスのインスタンスがセットされるはずである。また、Injectメソッドに渡されたオブジェクトは連鎖的にDIが行われる。そのためEmpLogicフィールドにセットされたEmployeeLogicのインスタンスのEmpDaoフィールドにも実装クラスのインスタンスがセットされる。
using System;
using System.Windows.Forms;
using Seasar.Quill;
namespace QuillSample
{
public partial class Form1 : Form
{
public IEmployeeLogic EmpLogic;
public Form1()
{
InitializeComponent();
// DIを行う
QuillInjector.GetInstance().Inject(this);
}
……省略…… |
|
InjectメソッドによるDIを行いたいオブジェクトを渡すだけ(Form1.cs) |
それでは実行してみよう。社員コードに何か数字を入力して社員検索ボタンをクリックすると、今度はNullReferenceException例外が発生せずに、検索結果を表示するTextBox(empNameTextBox)に「山田 太郎さん」と表示されたはずである。
このようにQuillを用いることで、ロジック部分は実装クラスに依存しないコーディングを行うことができる。ただしImplementation属性に実装クラスを指定する必要があるので、この部分に関しては依存が存在してしまう。ソース・コードを完全に依存しないようにしたい場合は、依存関係を設定ファイルに記述できるS2Containerを使うとよい。
ちなみに、もしインターフェイスを作成せずにクラスのみでDIを行う場合は、クラスにパラメータなしのImplementation属性を設定すればよい。
また、Quillがオブジェクトのインスタンスを作成してDIを行うわけだが、1度作成したインスタンスと同じ型のDIを要求された場合には、以前作成したインスタンスがDIされる。インスタンスの管理を行うDIコンテナは、普通、いくつかのインスタンス・モードを提供するが、Quillは常に同じインスタンスを返すsingletonモードしか提供していない。これはQuillがステートレスな(=状態をインスタンス変数に持たない)業務ロジックを構築するために作成されたからである。そのためQuillを利用する場合には常にステートレスなロジックの設計を行う必要がある。
最後にDIが有効となる例を取り上げよう。
Insider.NET 記事ランキング
本日
月間