我读了很多关于设计的最佳实践。最近,我遇到了Mark Seemann的this article。在这篇文章中他说
"您是否从类中提取接口以启用松散耦合? 如果是这样,您的接口之间可能存在1:1的关系 以及实现它们的具体类。这可能不是一个 好的迹象,违反了重用抽象原则(RAP)。我'已经 对此感到内疚,并不喜欢结果。"
现在,我已经使用Autofac多年来用于DI。我注意到为了实际实现一个具体的类作为接口我基本上必须违反这个"原则"通过为每个类创建接口,我需要在测试中交换实现或注入其他服务。
这样的例子如下:
builder.RegisterType<AcknowledgementRepository>()
.As<IAcknowledgementRepository>();
builder.RegisterType<ChangeLogRepository>()
.As<IChangeLogRepository>();
builder.RegisterType<HistoryCycleRepository>()
.As<IHistoryCycleRepository>();
这是我经常使用的非常常见的模式。但是,它似乎可能表明设计糟糕。
我对其他人如何避免创建这些&#34;标题&#34;感兴趣接口,似乎解决方案可能与使用.AsImplementedInterfaces()有关,但我还没有充分利用它。
编辑:我应该注意上面的存储库继承自IGenericRepository,但在很多情况下也会扩展它。
答案 0 :(得分:0)
我能够通过以下步骤简单地重构我的代码库来解决这个问题:
我的所有存储库都在实现IRepostory并继承了BaseRepository类,其中很少实际上覆盖了基本存储库中的任何功能。因此,我不是创建一堆I___Repositories,而是以这种方式使用autofac。
builder.RegisterType<MemberRepository>().As<IRepository<Member>>();
然后我不得不改变我的注射看起来像这样:
private readonly IRepository<Member> _memberRepo;
//constructor
public MyService(IRepostiory<Member> memberRepo)
{
_memberRepo = memberRepo;
}
我仍然在一些repos中有一些额外的功能,并意识到这些方法实际上表明一个存储库更像是数据字典的repoistory。所以,我创建了另一个名为ICustomDictionaryLookup
然后当我在autofac中注册我的服务时,我注册了每个接口的具体实现。
builder.RegisterType<DictionaryRepostiory>().As<IRepository<CustomDictionary>>();
builder.RegisterType<DictionaryRepostiory>().As<ICustomDicionary>();
这很好,因为它分离了抽象,并允许我灵活地选择哪些具体实现将实现特定功能。现在没有理由不能将DictionaryRepository注册为CRUD和另一个完全不同的ICustomDictionary。
仅依赖于检索自定义词典而不在字典表上执行CRUD操作的能力的方法甚至不需要知道基类中存在CRUD功能,因为它是无关紧要的。
我很高兴我沿着这条路走下去,因为我的代码要好得多。