SHOEISHA iD

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

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

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

japan.internet.com翻訳記事

階層化アーキテクチャと依存性注入・依存性逆転

アプリケーションを階層化して構築する考え方の紹介

階層化アーキテクチャによる責任の分割

 リスト1の主な問題点の1つは、単一責任の原則を完全に放棄していることです。単一責任の原則とは、簡単に言えば「あらゆるオブジェクトは責任を1つしか持ってはならず、したがって変更する理由は1つでなければならない」というものです。この原則に従っているコンポーネントは一般に、「凝集度の高い」コンポーネントと表現されます。

 もしも質問する機会があったなら、私は「この従業員表示Webページの主な責任は何ですか」と尋ねたことでしょう。この質問に対する答えはおそらく、「必要なのは従業員データをユーザーに表示することだけだ」となります。ところが、コードビハインド(code behind:分離コード)の内容を見ると、実態はまったく違っています。現在、このコンポーネントは従業員データをユーザーに表示するという1つの責任を負う代わりに、以下のすべての責任を負っています。

  • データベースへの接続を作成する
  • データベースから適切な情報を引き出すためのSQLステートメントを作成する
  • 高コストのリソース(接続やリーダーなど)を処理する
  • データベースの情報をデータのドメイン表現にマップする
  • ユーザーに情報を表示する

 この短いリストを見てもわかるように、このコンポーネントが負っている責任は多すぎます。さらに悪いことに、これらの責任のうち、従業員のリストを「表示する」ことに関係しているのは1つだけです。これでは凝集度が低いと思わざるを得ません。

 大多数の開発者は、アプリケーションにn層アーキテクチャという概念を導入することが、この問題の解決に役立つということにかなり前から気づいていました。要するに、階層化アーキテクチャを導入すれば、各層が(できるだけ実際的に)単一責任の原則をまっとうできるようになります。図2は、アプリケーションを構成する分離された層の概念図です。

図2 分離された層の関係図
図2 分離された層の関係図

 以下では、このアプリケーションの全面的なリファクタリングを試みることにします。Webページのコードビハインドにおける単一責任を実現するために、まずModel View Presenterデザインパターンの変形であるPassive Viewパターンを利用します。なお、Model View Presenterパターンの詳細については本稿では説明しませんので、私が昨年書いた記事を参照してください。

 最初に行うリファクタリングは、「従業員を表示する」という責任に直接関係しないコードを取り除くことです。実は、これによってコードビハインドからほぼすべてのコードを取り除くことになります。Webページの新たなコードビハインドは以下のようになります。

public partial class 
   ViewEmployeesWithAdditionOfPresenter : Page, 
   IEmployeeView
{
   private ViewEmployeesPresenterLowCohesion presenter;
   protected override void OnInit(EventArgs e)
   {
      base.OnInit(e);
      presenter = new 
      ViewEmployeesPresenterLowCohesion(this);
   }
   
   public IList Employees
   {
      set
      {
         this.employeesRepeater.DataSource = value;
         this.employeesRepeater.DataBind();
      }
   }
}

 リスト1と比べると、雲泥の差があるでしょう。Passive Viewパターンに不案内な方のために、ここで簡単に説明しておきます。

  • ビュー実装(Webページ)は、プレゼンターによってコンシュームされるインターフェイスを実装する。
  • ビューインターフェイスは、ビュー(Webページ)によって実装され、プレゼンターによってサブスクライブされるイベントを公開する。
  • ビューは自分自身について発生する事象(たとえば、「ボタンがチェックされた」とか「ロードが行われている」など)への応答としてイベントを発生させる。これらのイベントはプレゼンターによって処理される。
  • プレゼンターはイベントを処理する。また、ビューインターフェイスを使ってビューに情報を返すことがある。
  • ビューインターフェイスを使用すると、プレゼンターは任意のUIテクノロジ(たとえば、ASP.NET)との緩やかな結合を維持できる。

 リスト2に、この段階でのプレゼンタークラスを示します。

リスト2 最初のプレゼンター
public class ViewEmployeesPresenterLowCohesion
{
   private IEmployeeView view;
   private const string ConnectionString = 
      "data source=(local);Integrated Security=SSPI;" + 
      "Initital Catalog=NorthWind";
   private SqlConnection connection;
   public ViewEmployeesPresenterLowCohesion(
      IEmployeeView view)
   {
      this.view = view;
      HookupEventHandlersTo(view);
   }
   private void HookupEventHandlersTo(
      IEmployeeView view)
   {
      view.Load += delegate { LoadEmployees(); };
   }
   private void LoadEmployees()
   {
      if (view.IsPostBack) return;
      view.Employees = MapFrom(GetEmployees());
   }
   public DataTable GetEmployees()
   {
      using (connection = new SqlConnection(ConnectionString))
      {
         SqlCommand command = connection.CreateCommand();
         command.CommandText = "SELECT * FROM Employees";
         command.CommandType = CommandType.Text;
         connection.Open();
         using (SqlDataReader reader = 
            command.ExecuteReader(CommandBehavior.CloseConnection))
         {
            DataTable results = new DataTable();
            results.Load(reader);
            return results;
         }
      }
   }
   private IList<IEmployee> 
      MapFrom(DataTable employeeData)
   {
      List<IEmployee> employees = new List<IEmployee>();
      foreach (DataRow employeeRow in employeeData.Rows)
      {
         employees.Add(MapFrom(employeeRow));
      }
      return employees;
   }
   private Employee MapFrom(DataRow row)
   {
      return new Employee(Convert. ToInt32(row["EmployeeId"]), 
         row["LastName"].ToString(), row["FirstName"].ToString(), 
         row["Title"].ToString(), Convert.ToDateTime(row["BirthDate"]),
         Convert.ToDateTime(row["HireDate"]));
   }
}

 リスト2からわかるように、ここで行ったのは、もともとWebページのコードビハインドにあった雑多なものを別のクラスに移しただけのことです。ただ1つ注目してほしいのは、ここでビューのインターフェイスを導入することで、柔軟な階層化アーキテクチャを作成する際に重要となる「依存性逆転の原則」という概念を取り入れていることです。

次のページ
依存性逆転の原則

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

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

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

Jean-Paul S. Boodhoo(Jean-Paul S. Boodhoo)

.NET 1.0のベータ1から.NET Frameworkに従事してきた.NET開発のエキスパートで、アプリケーションのアーキテクチャ作成と設計と開発で7年以上の経験がある。アジャイルプラクティスと実際的なビヘイビア駆動開発(BDD)テクニックを通じてチームの成功を支援する独立コンサルタントとして活躍している。BDDを.NETに応用する記事をVisual Studio Magazine、DevX、MSDNに寄稿。ポッドキャス...

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

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

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1622 2007/09/04 14:00

イベント

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

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

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

メールバックナンバー