【发布时间】:2013-03-14 12:26:48
【问题描述】:
假设出于不同的原因我想对集合进行抽象操作:
现在为了简单起见,让我们对一个集合进行推理
class Book {
public string Title { get; set; };
public string SubTitle { get; set; }
public bool IsSold { get; set; }
public DateTime SoldDate { get; set; }
public int Volums { get; set; }
}
我的类型只需要搜索Book::Title(区分大小写或不区分大小写),因此我可以定义我的抽象:
interface ITitleSearcher {
bool ContainsTitle(string title);
}
然后实施
class CaseSensitiveTitleSearcher : ITitleSearcher { ... }
class NoCaseSensitiveTitleSearcher : ITitleSearcher { ... }
并将其用作
class TitleSearcherConsumer {
public TitleSearcherConsumer(ITitleSearcher searcher) { // <- ctor injection
}
}
直到这里我都清楚了,据我所知,Interface Segregation Principle 也被遵守了。
继续开发我必须满足其他要求,所以我定义然后实现其他接口,例如ITitleSearcher,例如:
class CaseSensitiveSubTitleSearcher : ISubTitleSearcher { ... }
class SoldWithDateRangeSearcher : ISoldDateRangeSearcher { ... }
为了不违反 DRY(不要重复自己),我可以围绕 IEnumerable<Book> 创建一个包装器:
class BookCollection : ITitleSearcher, ISubTitleSearcher, ISoldDateRangeSearcher
{
private readonly IEnumerable<Book> books;
public BookCollection(IEnumerable<Book> books)
{
this.books = books;
}
//...
}
现在,如果我有像 TitleSearcherConsumer 这样的消费者,我可以毫无问题地传递 BookCollection 的实例。
但如果我有这样的消费者:
class TitleAndSoldSearcherConsumer {
public TitleAndSoldSearcherConsumer(ITitleSearcher src1, ISoldDateRangeSearcher src2) {
}
}
我无法将BookCollection 实例注入TitleAndSoldSearcherConsumer ctor;我必须传递每个接口的实现。
是的,我可以用其他接口的所有方法定义一个IBookCollection,并在所有消费者中使用它,但这样做不违反ISP?
我可以同时靠近 ISP/SOLID 和 DRY 吗?
【问题讨论】:
-
我认为Specification Pattern 适合场景
标签: c# design-patterns dependency-injection abstraction