2013-04-22 51 views
1

我有兩個倉庫AlbumRepository與接口IAlbumRepositoryCachedAlbumRepository用具有構造接口IAlbumRepository接口IAlbumRepository。我需要注入Ninject ICachedAlbumRepositoryCachedAlbumRepository和構造函數與AlbumRepository如何使用戰略格局與Ninject

如何用Ninject實現它?

與結構圖同樣的方法

x.For<IAlbumRepository>().Use<CachedAlbumRepository>() 

.Ctor<IAlbumRepository>().Is<EfAlbumRepository>(); 

    public class CachedAlbumRepository : IAlbumRepository 
    { 
     private readonly IAlbumRepository _albumRepository; 

     public CachedAlbumRepository(IAlbumRepository albumRepository) 
     { 
      _albumRepository = albumRepository; 
     } 

     private static readonly object CacheLockObject = new object(); 

     public IEnumerable<Album> GetTopSellingAlbums(int count) 
     { 
      string cacheKey = "TopSellingAlbums-" + count; 

      var result = HttpRuntime.Cache[cacheKey] as List<Album>; 

      if (result == null) 
      { 
       lock (CacheLockObject) 
       { 
        result = HttpRuntime.Cache[cacheKey] as List<Album>; 

        if (result == null) 
        { 
         result = _albumRepository.GetTopSellingAlbums(count).ToList(); 

         HttpRuntime.Cache.Insert(cacheKey, result, null, 

          DateTime.Now.AddSeconds(60), TimeSpan.Zero); 
        } 
       } 
      } 

      return result; 
     } 
    } 

回答

3

您需要創建2個綁定 - 一個寫着注入CachedAlbumRepository到任何需要的IAlbumRepository,另一種是說注入正常AlbumRepositoryCachedAlbumRepository。這些綁定應該這樣做:

Bind<IAlbumRepository>() 
    .To<CachedAlbumRepository>(); 

Bind<IAlbumRepository>() 
    .To<AlbumRepository>() 
    .WhenInjectedInto<CachedAlbumRepository>(); 
2

我不能回答這個問題你,但我對你有一些反饋。

您的應用程序設計失去了一個很好的機會。它錯過了機會,並保持可持續性。既然你定義了一個裝飾器(CachedAlbumRepository是一個decorator),你也可能會開始爲其他的存儲庫編寫裝飾器。我想你有一個裝飾器爲你的IArtistRepository,IRecordLabelRepository

必須實施這些重複的存儲庫是違反DRY原則。但違反DRY實際上是由違反其他一些原則造成的。您的設計違反了一些SOLID原則,即:

  1. 您的設計違反了Single Responsibility Principle,因爲你將你的資料庫(如GetTopSellingAlbums法)內放置查詢方法都不是很有凝聚力。換句話說,您的存儲庫類會變得很大,並且會做太多,開始難以閱讀,難以測試,難以改變並且難以維護。
  2. 您的設計違反了Open/closed principle,因爲每次向系統添加新查詢時都必須更改存儲庫。這意味着改變界面,改變裝飾器,改變真實的實現,並改變系統中存在的每一個假實現。
  3. 您的設計違反了Interface Segregation Principle,因爲您的存儲庫接口會變寬(將有很多方法),並且這些接口的使用者被迫依賴於他們不使用的方法。這使得實現裝飾器和編寫假對象變得越來越困難。

解決這個問題是躲在一個單一的通用抽象所有存儲庫:

public interface IRepository<TEntity> 
{ 
    void Save(TEntity entity); 
    TEntity Get(Guid id); 
} 

由於這是一個通用的接口,它不會給你任何空間添加任何實體,具體查詢方法,這是很好的。這很好,因爲IRepository<T>會變窄而且穩定。這使得添加裝飾器非常容易(如果你仍然需要在這裏添加裝飾器)。

訣竅是阻止向此接口添加查詢方法(並且不從此接口繼承新接口),而是爲系統中的每個查詢提供自己的類。或者實際上,兩個班。一個類定義了數據,另一個類知道如何執行該查詢。最後但並非最不重要的是,您可以將每個類隱藏在查詢的同一抽象背後(就像我們對存儲庫有一個通用抽象一樣)。當你這樣做時,你只需要定義一個單一的緩存修飾器,你可以將它應用於系統中的任何查詢子集。

您可以在detail about this design here中閱讀。起初這看起來有點抽象,但我向你保證,當你掌握了這一點時,你不可能回到你的舊設計。

+1

好的提示史蒂文。謝謝! – Reno 2013-04-23 08:14:16