ASP.NET MVC開発:依存注入
11703 ワード
依存注入とは
依存注入(Dependency injection,DI)は、オブジェクトとその協力者または依存項目との間のばらばらな結合を実現する技術である.直接インスタンス化したり、静的参照を使用したりするのではなく、クラスがその操作(Action)を実行するために使用されるオブジェクトは、クラスに何らかの方法で提供されます.通常、クラスはそのコンストラクション関数によって依存関係を宣言し、表示依存原則(Explicit Dependencies Principle)に従うことができます.この方法を「コンストラクション関数注入(constructor injection)」と呼ぶ.
クラスの設計がDI思想を用いると,それらの結合は,それらの協力者に直接ハードコーディングに依存しないため,より緩やかになる.これは、「上位モジュールは下位モジュールに依存すべきではなく、両方とも抽象に依存すべきだ」という依存逆転の原則に従う.クラスは、特定のインプリメンテーションを参照するのではなく、構築時に抽象(通常interfaces)を提供することを要求します.インタフェースの依存関係を抽出し、これらのインタフェースを提供する実装も、ポリシー設計モード(Strategy design pattern)の一例である.
システムがDIを使用するように設計されると、多くのクラスがそれらのコンストラクション関数(または属性)によって依存関係を要求し、これらのクラスとそれに関連する依存関係を作成するために使用されるクラスが役立つ.これらのクラスは、コンテナ(containers)と呼ばれるか、より具体的には、制御反転(Inversion of Control,IoC)コンテナまたは依存注入(Dependency injection,DI)コンテナと呼ばれる.コンテナは本質的に工場であり、要求されたタイプのインスタンスを提供します.特定のタイプが依存関係を宣言し、コンテナが依存タイプを提供するように構成されている場合、依存関係の作成をリクエストインスタンスの作成の一部とします.このようにして、ハードコーディングのタイプ構造を必要とせずに、タイプに複雑な依存関係を提供することができる.コンテナは、オブジェクトの依存関係を作成するだけでなく、アプリケーション内のオブジェクトのライフサイクルも管理します.
ASP.NET Coreは、デフォルトでコンストラクション関数注入をサポートする単純な内蔵コンテナ(IServiceProviderインタフェースで表される)を含み、ASP.NETにより、一部のサービスをDIで取得することができる.ASP.NETのコンテナとは、その管理タイプがservicesであることを意味します.この文章の中で、私達は主にソフトウェアの設計のモードを討論して、それによって簡単にASP.を理解しますNET MVCの依存注入.
設計モード-制御反転モード
1つのコンポーネントが他のコンポーネントに依存する場合,結合と呼ぶことを知った.1つのクラスは、それと相互作用するクラスの多くの情報を知っており、高結合(または緊密結合)と呼ばれています.
EmailServicesという名前のクラスを新規作成しました.csコードは以下の通りです.
public class EmailService
{
public void SendMessage()
{
..//
JavaScript.ConsoleLog("EMail ");
}
}
新しいNotificationSystemを作成します.cs、コードは以下の通りです.
public class NotificationSystem
{
private EmailService svc;
public NotificationSystem()
{
svc = new EmailService();
}
public void Notificationsend()
{
svc.SendMessage();
}
}
この例では、NotificationSystemクラスはEmailServiceクラスに依存しており、この結合は高結合とみなされます.
次にimessageingServicesを新規作成します.csクラスは、インタフェースとして使用されます.
public interface imessageingService
{
void SenMessage();
}
EmailServiceクラスを変更します.
public class EmailService:imessageingService
{
public void SendMessage()
{
JavaScript.ConsoleLog("EMail ");
}
}
最後にNotificationSystemクラスを変更します.
public class NotificationSystem
{
private imessageingService svc;
public NotificationSystem()
{
svc = new EmailService();
}
public void Notificationsend()
{
svc.SendMessage();
}
}
テストの実行に成功しました.この例では、JavaScriptの静的クラスを使用してJavaScript.をテストしました.ConsoleLogはconsoleを実現する.logの書き込み.(実は意味がないので、単純にクラス、インタフェース間が正しく動作しているかどうかを見てみましょう)
using System.Web;
public static class Javascript{
static string scriptTag = "{0} ";
public static void ConsoleLog(string message)
{
string function = "console.log('{0}');";
string log = string.Format(GenerateCodeFromFunction(function), message);
HttpContext.Current.Response.Write(log);
}
public static void Alert(string message)
{
string function = "alert('{0}');";
string log = string.Format(GenerateCodeFromFunction(function), message);
HttpContext.Current.Response.Write(log);
}
static string GenerateCodeFromFunction(string function)
{
return string.Format(scriptTag, function);
}}
(静態類の使用はかなりDIではありません~~!)
次に、コードを可視化して製品クラスを作成し、クラスと依存クラスの結合を低減する方法を見てみましょう.
Visual Studioを実行し、「DI」という項目を作成し、「テンプレートの選択」ウィンドウで「Emptyテンプレート」を選択し、次の項目にフォルダとコア参照を追加する場合はMVCを選択します.
プロジェクトのModelsフォルダに新しいクラスを追加します:Product.cs、コードは以下の通りです.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace IDTest.Models
{
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
}
簡単なカートプログラムを構築したいのですが、まずPriceフィールドSUMで計算されたクラスと製品数を計算するクラスを構築する必要があります.この2つのクラスはそれぞれLinqCalcCountと名付けられています.csとLinqCalcSum.cs、次はコードです.
public class LinqCalcSum
{
public decimal ValueProducts(IEnumerable products)
{
return products.Sum(p => p.Price);
}
}
public class LinqCalcCount
{
public int ValueProducts(IEnumerable products)
{
int count = products.Count();
return count;
}
}
次はショッピングカートのクラスを作り、ShoppingCartと名付けます.cs:
public class ShoppingCare
{
private LinqCalcSum c_sum;
private LingCalcCount c_count;
public ShoppingCare(LinqCalcSum Csum)
{
c_sum = Csum;
}
public ShoppingCare(LinqCalcCount Ccount)
{
c_count = Ccount;
}
public IEnumerable products { get; set; }
public decimal CalculateProductSum()//
{
return c_sum.ValueProducts(products);
}
public int CalculateProductCount()//
{
return c_count.ValueProducts(products);
}
次に、新しいコントローラの名前を「HomeController」と呼ぶコントローラが必要です.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DI.Models;
namespace DI.Controllers
{
public class HomeController : Controller
{
// GET: Home
private Product[] products = {
new Product {Name=" ",Category=" ",Price=100M},
new Product {Name=" ",Category=" ",Price=98M},
new Product {Name=" ",Category=" ",Price=580M},
new Product {Name=" ",Category=" ",Price=199M},
};
public ActionResult Index()
{
return View(products);
}
public ActionResult SUM()
{
LinqCalcSum ProductSum = new LinqCalcSum();
ShoppingCare SC = new ShoppingCare(ProductSum)
{
products = products
};
decimal totalValue = SC.CalculateProductSum();
return View(totalValue);
}
public ActionResult Count()
{
LinqCalcCount Productcount = new LinqCalcCount();
ShoppingCare SC = new ShoppingCare(Productcount)
{
products = products
};
int totalINT = SC.CalculateProductCount();
return View(totalINT);
}
}
}
最後に、4つのすべてのデータを表示するビューを作成し、Index()を右クリックして新しいビューを作成します.
@model IEnumerable
@{
Layout = null;
}
Index
@{
foreach (DI.Models.Product item in Model)
{
}
}
:
:
:
@item.Name
@item.Category
¥:@item.Price
私たちは2つのビューを再構築して、1つのSUM、1つのCount、実はすべてとても簡単です
@model decimal
:@Model
model int
@Model 。
最終的な出力結果は次のとおりです.
総数は¥977で、全部で4件のデータがあります.
(単純にデータを計算したいだけなら、そんなに複雑ではなく、Index()ビューにLINQ関数を入れておけばいいので、次のコードを見てみましょう)
@Model.Count()
¥:@Model.Sum(p => p.Price)
(ただし、この例は単にこの機能を実現したいのではなく、この例を通して制御反転モードについて議論したい)
このルーチンから,Shopping,CartLinqCalcCount.csとLinqCalcSum.csか、コントローラとShoppingCart、LinqCalcCount.cs、LinqCalcSum.cs間はいずれも高結合クラスであり,次にインタフェースを用いて,一部の問題を解決することを望んでいる.Modlesフォルダに新しいクラスを作成し、ICalculatorSUMと名付けました.csとICalculatorCount.cs、コードは以下の通りです.
public interface ICalculatorSUM
{
decimal valueproducts(IEnumerable products);
}
public interface ICalculatorCount
{
int valueproducts(IEnumerable products);
}
次にLinqCalcSum、LinqCalcCountクラスでこのインタフェースを実装し、この2つのファイルを変更します.
public class LingCalcCount:ICalculatorCount
{
public int valueproducts(IEnumerable products)
{
int count = products.Count();
return count;
}
}
public class LinqCalcSum:ICalculatorSUM
{
public decimal valueproducts(IEnumerable products)
{
return products.Sum(p => p.Price);
}
}
次に、ShoppingCartクラスを変更し、ShoppingCartとLinqValue Calculatorの緊密な結合関係をインタフェースで遮断します.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace DI.Models
{
public class ShoppingCare
{
private ICalculatorSUM c_sum;
private ICalculatorCount c_count;
public ShoppingCare(ICalculatorSUM Csum)
{
c_sum = Csum;
}
public ShoppingCare(ICalculatorCount Ccount)
{
c_count = Ccount;
}
public IEnumerable products { get; set; }
public decimal CalculateProductSum()//
{
return c_sum.valueproducts(products);
}
public int CalculateProductCount()
{
return c_count.valueproducts(products);
}
}
}
コントローラでもSUM()とCount()のコードを変更します.
public ActionResult SUM()
{
ICalculatorSUM ProductSum = new LinqCalcSum();
ShoppingCare SC = new ShoppingCare(ProductSum)
{
products = products
};
decimal totalValue = SC.CalculateProductSum();
return View(totalValue);
}
public ActionResult Count()
{
ICalculatorCount Productcount = new LingCalcCount();
ShoppingCare SC = new ShoppingCare(Productcount)
{
products = products
};
int totalINT = SC.CalculateProductCount();
return View(totalINT);
}
ShoppingCartとLinqValueCalculatorの緊密な結合が解除されたように見えます.
上述した部分的緩和結合は明らかに我々が必要としない.必要なのは、クラス内で、オブジェクトのインスタンスを作成することなく、公開インタフェースを実装したオブジェクトの参照を得ることができることです.このような「必要」をDI(依存注入,Dependency Injection)と呼び,いわゆるIoC(制御反転,Inversion of Control)という意味である.
DIはインタフェースによる松結合を実現する設計モードである.初心者は、ネット上でなぜそんなに多くの技術文章がDIというものに大いに興味を持っているのか、DIがほとんどのフレームワークに基づいてアプリケーションを効率的に開発するには、MVC開発を含む開発者が必要とする重要な理念であるからだ.それはデカップリングの重要な手段である.
プログラミングでDIを使用することが多いため、UnityやNinjectなど、DIの補助ツール(またはDIコンテナ)が登場します.
参考書には『ASP.NET MVC 5プレミアムプログラミング(第5版)』『ASP.NET MVC 5に精通している』などがある.
ご支援ありがとうございます.投稿するときは涼しい風を楽しんでください.Netで署名します.自由転載-非商用-非派生-署名保持(クリエイティブ共有3.0ライセンス)