3

我相信这个问题是不言自明的。我宁愿把更多的注意力放在例子上来支持问题。

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

public interface ICollection : IEnumerable
{
    void CopyTo(Array array, int index);
    int Count { get; }
    Object SyncRoot { get; }
    bool IsSynchronized { get; }
}

public interface IList : ICollection
{
    Object this[int index] { get; set; }
    int Add(Object value);
    bool Contains(Object value);
    void Clear();
    bool IsReadOnly { get; }
    bool IsFixedSize { get; }
    int IndexOf(Object value);
    void Insert(int index, Object value);
    void Remove(Object value);
    void RemoveAt(int index);
}

很明显,它IEnumerable是分开的,只允许循环遍历集合。但我不明白他们为什么保持ICollectionIList分开?即使它们是一个,IList 也不会变胖,因为任何集合总是需要这种行为?

我遇到了这篇IEnumerable文章,它说如果客户端只需要循环项目,ICollection如果只需要只读访问等等,你的 API 就会返回。

MSFT 为何如此完美地应用 ISP,以至于这些年来从未引起任何问题?

应用 ISP 是基于客户端代码需求的持续过程还是一次性应用程序?如果 ISP 只应用一次,那么我的问题在于帖子标题本身。

4

1 回答 1

2

我不明白为什么他们保持ICollectionIList分开?

IList是一个集合,其中通过索引获取项目是合乎逻辑的。将其分离为子接口是为了认识到存在未定义索引的其他集合这一事实。ISet是此类集合的一个示例。

由于必须实现以下四种方法,因此合并会对一个人以干净方式ICollection定义的IList能力产生负面影响:ISet

this[int index]
int IndexOf(Object value)
void Insert(int index, Object value)
void RemoveAt(int index)

另一方面,人们可以合理地争辩说,方法

int Add(Object value);
bool Contains(Object value);
void Clear();
bool IsReadOnly { get; }
bool IsFixedSize { get; }
void Remove(Object value);

可能属于ICollection接口。

接口隔离原则 - 如何决定隔离什么?

回想起来,当班级到位时,决定要隔离什么的任务要容易得多。查看是否需要任何类来引发未实现的异常。这些方法是移动到需要引入的子界面的主要候选方法。

例如,考虑开始一个设计,将IList方法移到ICollection中,并且没有IList子接口。您可以使用这两个接口成功构建 List和类。LinkedList

现在考虑添加HashSet到混合物中。这个类必须实现四个与集合集合格格不入的方法,这表明您应该考虑添加一两个子接口——一个用于列表,另一个用于集合。

在你有任何类之前决定隔离要困难得多,因为你的接口倾向于满足需要使用它的特定类的需求。从扁平化的界面结构开始,并在后续版本中通过重构对其进行扩展的情况并不少见。

于 2016-06-17T19:15:55.920 回答