1

我有两个AlbumRepository带有接口的存储库IAlbumRepositoryCachedAlbumRepository带有IAlbumRepository构造函数接口的接口IAlbumRepository。我需要用 Ninject 注入,ICachedAlbumRepository用.CachedAlbumRepositoryAlbumRepository

如何用 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;
        }
    }
4

2 回答 2

3

您需要创建 2 个绑定 - 一个说注入CachedAlbumRepository到需要的任何东西中,IAlbumRepository另一个说注入法线AlbumRepositoryCachedAlbumRepository. 这些绑定应该这样做:

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

Bind<IAlbumRepository>()
    .To<AlbumRepository>()
    .WhenInjectedInto<CachedAlbumRepository>();
于 2013-04-22T18:19:18.357 回答
2

我不能为你回答这个问题,但我有一些反馈给你。

您的应用程序设计错过了一个很好的机会。它错过了保持可维护性的机会。由于您定义了一个装饰器(这CachedAlbumRepository是一个装饰器),您可能也会开始为其他存储库编写装饰器。我想你有一个装饰器来装饰你的IArtistRepository,IRecordLabelRepository等等。

必须实现这些重复的存储库是违反DRY原则的。但是违反 DRY 其实是因为违反了其他一些原则。您的设计违反了一些SOLID原则,即:

  1. 您的设计违反了单一职责原则,因为您将放置在存储库中的查询方法(例如GetTopSellingAlbums方法)不是很有凝聚力。换句话说,您的存储库类会变得很大并且会做太多事情,并且开始变得难以阅读、难以测试、难以更改和难以维护。
  2. 您的设计违反了开放/封闭原则,因为每次向系统添加新查询时都必须更改存储库。这意味着改变接口,改变装饰器,改变真正的实现,改变系统中存在的每一个假实现。
  3. 您的设计违反了接口隔离原则,因为您的存储库接口将变宽(将有许多方法)并且这些接口的使用者被迫依赖于他们不使用的方法。这使得实现装饰器和编写假对象变得越来越难。

这个问题的解决方案是将所有存储库隐藏在一个通用抽象后面:

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

由于这是一个通用接口,它不会给您任何空间来添加任何特定于实体的查询方法,这很好。这很好,因为它IRepository<T>会窄而稳定。这使得添加装饰器变得非常容易(如果您仍然需要在此处添加装饰器)。

诀窍是防止向该接口添加查询方法(并且不要从该接口继承新接口),而是为系统中的每个查询赋予其自己的类。或者实际上是两个类。一个具有数据定义的类,一个知道如何执行该查询的类。最后但并非最不重要的一点是,您可以将每个类隐藏在查询的相同通用抽象后面(就像我们对存储库有一个通用抽象一样)。当你这样做时,你只需要定义一个可以应用于系统中任何查询子集的缓存装饰器。

您可以在此处详细了解此设计。起初这可能看起来有点抽象,但我向你保证,当你掌握了这个窍门时,你将永远无法回到你的旧设计。

于 2013-04-22T19:09:11.613 回答