2013-04-22 44 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