SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

S2Container.NETのDIとAOPを活用し生産性の高いシステムを構築する

.NET環境でDIコンテナとAOPの機能を提供するフレームワークを利用する


  • このエントリーをはてなブックマークに追加

「Seasar2」は、DIコンテナとAOPという便利な機能を提供するJavaのオープンソースのフレームワークで、今後の開発の中心となる基盤として注目を集めています。本稿では「Seasar2」を.NET環境に移植した「S2Container.NET」と呼ばれるプロダクトを紹介します。

  • このエントリーをはてなブックマークに追加

はじめに

 『システム構築の現場にもっと「易しさ」と「優しさ」を』というコンセプトのもとに開発が進められている「Seasar2」というオープンソースをご存知でしょうか。「Seasar2」はDIコンテナとAOPという便利な機能を提供するJavaのフレームワークで、今後の開発の基盤として注目を集めています。本稿では「Seasar2」を.NET環境に移植した「S2Container.NET(以降s2dotnet)」と呼ばれるプロダクトを紹介します。

対象読者

 .NETにて開発を行っている方で、設計やフレームワークなどに興味を持っている方を対象とします。

必要な環境

 サンプルはVisual Studio .NET 2003で作成され、.NET Framework 1.1、s2dotnet 1.0.0で動作確認をしています。

s2dotnetとは

 「s2dotnet」は、杉本和也氏と佐藤太一氏が中心となって「Seasar2」を.NET環境に移植したフレームワークです。s2dotnetを使用すると、DIコンテナとAOPの機能を、.NET環境で簡単に利用することができます。

DI(Dependency Injection)コンテナとは

 「DI(Dependency Injection)」とは、インターフェースと実装を分離して、オブジェクトを外部から生成し設定する仕組みです。インターフェースと実装を分離するという考え方は以前からありましたが、これまではソースコードのどこかに実装へ依存する記述が必要でした。しかしDIコンテナを用いると、設定ファイルに基づいて、実行時に依存関係(実装クラス)を注入することが可能になります。

AOP(Aspect Oriented Programming)とは

 「AOP(アスペクト指向プログラミング)」とは、複数のクラスに適用される共通の処理を、外から織り込む考え方です。AOPを用いると、ログ出力やトランザクション管理のような冗長な処理を1箇所に記述し、その処理を複数のクラスの任意のメソッドに織り込むことができるようになります。

s2dotnetの入手とセットアップ

 s2dotnetは、s2dotnetのWebサイトの「ダウンロード」のリンクから入手します。執筆時点での最新バージョンは1.0.0です。

 ダウンロードしたファイルを解凍した「Release」フォルダにs2dotnet本体の「Seasar.dll」があります。Visual Studioの場合、ソリューションエクスプローラの[参照設定]を右クリックして、[参照の追加]から「Seasar.dll」を選択します。その際、リソースファイルの「ja-JP」フォルダを「Seasar.dll」と同じフォルダに配置するようにしてください。またlog4netも必要になりますので「log4net.dll」を同じフォルダに配置してください。

s2dotnetを用いるメリット

インターフェースと実装を分離した設計

 DIコンテナを用いて開発を行うには、インターフェースと実装を分離して設計することが重要になります。インターフェースと実装を分離すると、仕様の変更による影響を受けにくくなるというメリットがあります。

 ここでは、RDBMSのアクセスに使用する「Connection」を例に見てみましょう。s2dotnetを活用すれば、RDBMSの変更があったとしてもソースコードを変更しなくても済むようになります。

 以下のような、SQL Serverに接続するClass1Hogeメソッドがあったとします。

「Class1.cs」(SQL Server接続:インターフェースと実装が分離されていない状態)
public void Hoge()
  string conStr = "Server=localhost;database=Northwind;"
    + "User ID=sa;Password=admin";
  System.Data.SqlClient.SqlConnection Conn =
    new System.Data.SqlClient.SqlConnection(conStr);
  Conn.Open();
}

 もし、RDBMSをSQL ServerからOLE DB(MDB)に変更することになった場合には、「conStr」の接続文字列と「System.Data.SqlClient.SqlConnection」の部分を「System.Data.OleDb.OleDbConnection」へ書き換える必要があります。

「Class1.cs」(MDB接続:インターフェースと実装が分離されていない状態)
public void Hoge()
  string conStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
    + "User ID=Admin;Data Source=./s2dotnet.mdb";
  System.Data.OleDb.OleDbConnection Conn =
    new System.Data.OleDb.OleDbConnection(conStr);
  Conn.Open();
}

 そこで、インターフェースを使用するとプログラムの修正範囲を軽減することができます。この場合、変数の宣言部をSystem.Data.SqlClient.SqlConnectionSystem.Data.OleDb.OleDbConnectionのインターフェースであるSystem.Data.IDbConnectionに変更します。

「Class1.cs」(MDB接続:変数に「IDbConnection」インターフェースを使用した状態)
public void Hoge()
  string conStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
  + "User ID=Admin;Data Source=./s2dotnet.mdb";
  System.Data.IDbConnection Conn =
    new System.Data.OleDb.OleDbConnection(conStr);
  Conn.Open();
}

 Conn.Open()といったプログラム部は問題なく動作するため、変数Connをインターフェースに変更することは問題ありません。しかし、実装クラス(「new」の後ろの部分)の変更時にはプログラムの修正が必要になります。そこで、s2dotnetを使用して実装クラスを外から設定するようにしてみましょう。

 ここでは、実装クラスの記述を削除し、Connプロパティを作成します。

「Class1.cs」(MDB接続:s2dotnetを利用してインターフェースと実装を分離した状態)
//プロパティ
private System.Data.IDbConnection _conn;
public System.Data.IDbConnection Conn
{
  set{_conn = value;}
}
//処理
public void Hoge()
  _conn.Open();
}

 続けて、s2dotnetの設定ファイルを記述します。

s2dotnetの設定ファイル(DI)
<!-- 「OleDbConnection」の定義 -->
<component name="OleDbConn" class="System.Data.OleDb.OleDbConnection">
  <!--コンストラクタの引数にConectionStringを設定してインスタンス化-->
  <arg>"Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;
  Data Source=./s2dotnet.mdb"</arg>
</component>

<!-- 「Class1」の定義 -->
<component name="Class1" class="S2dotnetSimpleSample.Class1">
  <!--プロパティ「Conn」にOleDbConnを注入-->
  <property name="Conn">OleDbConn</property>
</component>


 s2dotnetからClass1を取得するとConnプロパティにSystem.Data.OleDb.OleDbConnectionが注入されるようになります。そのため、OracleやMySQLといった他のRDBMSを使用することになったとしても、実装クラスがIDbConnectionを継承していれば、設定ファイルを変更するだけで済みます。

 もしかしたらプログラムが複雑になったと感じた読者もいらっしゃるかもしれません。しかし、これまでの開発では、必要とするクラスを取得するために実装クラスをハードコーディングするか、取得用のロジックを記述しなければいけませんでした。s2dotnetを用いると、コンストラクタやプロパティを経由して、必要とするクラスのインスタンスを自動で注入できるようになるので、むしろプログラムはシンプルになると言えるでしょう。

 インターフェースと実装を分離して、DIコンテナによって注入するメリットを整理してみましょう。

  1. メンテナンス性の向上
  2. ……インターフェースベースのプログラミングにより、実装クラスの変更による影響を極小化できます。
  3. 品質の向上
  4. ……実装クラスの変更が行いやすく特定の実行環境に依存しないため、テストが簡単にできるようになります。
  5. 開発期間の短縮
  6. ……使いたい機能の実装が出来上がっていなくてもMockの利用が簡単なため、並行して作業できるようになります。
  7. 再利用性の向上
  8. ……オブジェクトは通常のクラスであり特定のAPIに依存しないので、再利用できる機会が増えます。

 なお、実際の開発でデータベースに接続する時には、s2dotnetから提供されている「Seasar.Extension.ADO.IDataSource」や後述する自動ローカルトランザクションを使用すると良いでしょう。

AOPを用いた設計

 AOP(アスペクト指向プログラミング)とは、複数のクラスに適用される共通の処理を、外から織り込む考え方です。ここでは、ログの出力機能をAOPする例を見てみましょう。

s2dotnetの設定ファイル(AOP)
<!-- 「TraceInterceptor」の定義 -->
<component name="traceInterceptor"
  class="Seasar.Framework.Aop.Interceptors.TraceInterceptor" />

<!-- 「Class1」の定義 -->
<component name="Class1"  class="S2dotnetSimpleSample.Class1">
  <aspect>traceInterceptor</aspect>
</component>

 s2dotnetの設定ファイルに「<aspect>traceInterceptor</aspect>」という記述をすることにより、ログ出力処理がClass1に織り込まれます。この結果、Class1のメソッドが呼び出される前後に、以下のトレースログが出力されるようになります。

BEGIN S2dotnetSimpleSample.Class1#Hoge()
END S2dotnetSimpleSample.Class1#Hoge() :

 従来の開発では、対象クラスのメソッド全てにログ出力命令をプログラムする必要がありましたが、AOPを活用すれば設定ファイルを変更するだけで、様々な処理を複数のクラスに織り込むことが可能になります。また、データベースのトランザクションをAOPによって制御することも可能になります。「try~catch」命令を書かなくとも、トランザクション開始・コミット・ロールバックの制御ができるため大変便利です。

 それでは、AOPのメリットを整理しましょう。

  1. 業務ロジックから冗長的な処理が排除されるため、シンプルなプログラムになります。
  2. システム的な処理を外出しして分離することで、メンテナンス性が向上します。

 なお、s2dotnetでAOPを適用するには、System.MarshalByRefObjectの派生クラスであるか、 インターフェース型でクラスを受け取る必要がありますのでご注意ください。

 なお、ここまでのプログラムのサンプルは「S2dotnetSimpleSample.zip」をご覧ください。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
サンプルアプリケーションの概要

修正履歴

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 青木 淳夫(アオキ アツオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLDB/PEAR/Smarty)」「独習シリーズ(ASP.NET/PHP)」「10日でおぼえる入門教室シリーズ(ASP.NET/PHP/Jakarta/JSP&サーブレット/XML)」「Pocket詳解辞典シリーズ(ASP.NET/PHP/Perl&CGI)」「今日からつかえるシリーズ(PHP/JSP&サーブレット/XML/ASP)」「書き込み式 SQLのドリル」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/180 2006/12/22 18:44

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング