這次要介紹的是一個非常不錯的DI(即依賴注入)架構,就是Ninject,通過使用此架構,可以非常方便地實現DI。不過在介紹此架構之前,先讓我們再來看看到底為什麼要使用依賴注入和其具體實現吧。
請大家先看以下代碼,我們先建立最基本的產品類,然後添加一個價格計算介面和一個實現此介面的類:
//產品類
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 { set; get; }
}
//價格計算介面
public interface IValueCalculator
{
decimal ValueProducts(params Product[] products);
}
//實現價格計算介面
public class LinqValueCalculator : IValueCalculator
{
public decimal ValueProducts(params Product[] products)
{
return products.Sum(p => p.Price);
}
}
接下來再建立購物車類,然後將以上介面添加進去:
public class ShoppingCart
{
private IValueCalculator calculator;
public ShoppingCart(IValueCalculator calcParam)
{
calculator = calcParam;
}
public decimal CalculateStockValue()
{
// 定義和設定產品資訊
Product[] products =
{
new Product() { Name = "Kayak", Price = 275M},
new Product() { Name = "Lifejacket", Price = 48.95M},
new Product() { Name = "Soccer ball", Price = 19.50M},
new Product() { Name = "Stadium", Price = 79500M}
};
// 計算總價格
decimal totalValue = calculator.ValueProducts(products);
// 返回計算結果
return totalValue;
}
}
從以上代碼可看出,ShoppingCart和LinqValueCalculator都依賴於IValueCalculator介面,但ShoppingCart和LinqValueCalculator之間並沒有直接關係,甚至ShoppingCart並不知道LinqValueCalculator的存在,這樣的好處也顯而易見,就是LinqValueCalculator可以隨時更換而不會影響到ShoppingCart裡的代碼,因此也達到了松耦合的效果了。
以下是上面幾個類的關係圖:
OK,現在看看如何結合Ninject來使用以上代碼。首先要為你的項目添加Ninject引用,在項目名稱裡點擊右鍵,然後選擇“Add PackageLibrary Reference”,然後只需在搜尋方塊裡輸入 ninject ,這時就可看到下面的挑選清單裡出現了 Ninject的項目了,直接選擇安裝即可
為了方便示範,只需建立一個控制台項目即可。要使用Ninject,可直接調用IKernel介面,代碼如下:
class Program
{
static void Main(string[] args)
{
IKernel ninjectKernel = new StandardKernel();
//綁定介面到實作類別裡
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator<();
}
}
以上代碼將介面與實作類別綁定起來了,然後再添加以下代碼以實現ShoppingCart類:
// 擷取實現的介面
IValueCalculator calcImpl = ninjectKernel.Get<IValueCalculator>();
// 建立執行個體注入到 ShoppingCart
ShoppingCart cart = new ShoppingCart(calcImpl);
// 執行計算功能以輸出結果
Console.WriteLine("Total: {0:c}", cart.CalculateStockValue());
可能大家會感覺這樣使用還不如直接調用來得方便啊,如果不使用 Ninject ,我們只需直接使用:
ShoppingCart cart = new ShoppingCart(new LinqValueCalculator());
這樣就可以了,不是方便很多嗎?為什麼還要用Ninject寫這麼多代碼呢?
嗯,以上其實只是一個最簡單的為了示範的代碼,如果隨著複雜的多層介面的注入增加的話,就可以馬上體現出Ninject的效率和好處了!
請繼續看以下代碼,我們再添加一個新的折扣介面:
//添加折扣介面
public interface IDiscountHelper
{
decimal ApplyDiscount(decimal totalParam);
}
//實現不同的折扣
public class DefaultDiscountHelper : IDiscountHelper
{
public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (10m / 100m * totalParam));
}
}
//為之前的價格功能裡添加折扣功能,實現折扣介面
public class LinqValueCalculator : IValueCalculator
{
private IDiscountHelper discounter;
public LinqValueCalculator(IDiscountHelper discountParam)
{
discounter = discountParam;
}
public decimal ValueProducts(params Product[] products)
{
return discounter.ApplyDiscount(products.Sum(p => p.Price));
}
}
現在我們又多了一層注入的介面了,但使用Ninject的話就非常方便,只需添加多一行代碼就可以了:
...
IKernel ninjectKernel = new StandardKernel();
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
//這是為新介面添加的,其他代碼均不需改動
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
// 擷取實現的介面
IValueCalculator calcImpl = ninjectKernel.Get<IValueCalculator>();
ShoppingCart cart = new ShoppingCart(calcImpl);
Console.WriteLine("Total: {0:c}", cart.CalculateStockValue());
...
隨著代碼介面的複雜性增多,就可以體現出Ninject的好處了
ASP.NET MVC中應用:
namespace NinjectDemo.Infrastructure
{
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null
? null
: (IController)ninjectKernel.Get(controllerType);
}
private void AddBindings()
{
// put additional bindings here
ninjectKernel.Bind<IProductRepository>().To<FakeProductRepository>();
}
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
}
引用:http://www.coderblog.in/2011/09/using-ninject-for-di.html