关于c#:接口隔离原则 – 如何决定隔离什么?

Interface Segregation Principle - How to decide what to segregate?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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分开?即使他们是一个,我也不会变胖,因为任何收集都需要这种行为?

我看到这篇文章说,如果客户只需要循环项目,您的API将返回IEnumerable,如果只需要只读访问,则返回ICollection,依此类推。

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

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


I don't understand why they kept ICollection and IList separate?

IList是一个集合,通过索引获取一个项目具有逻辑意义。将它分离成子接口是为了认识到存在索引未定义的其他集合这一事实。ISet就是这种收集的一个例子。

合并ICollectionIList将对一个人以干净的方式定义ISet的能力产生负面影响,因为必须执行这四种方法:

1
2
3
4
this[int index]
int IndexOf(Object value)
void Insert(int index, Object value)
void RemoveAt(int index)

另一方面,人们可以合理地认为

1
2
3
4
5
6
int Add(Object value);
bool Contains(Object value);
void Clear();
bool IsReadOnly { get; }
bool IsFixedSize { get; }
void Remove(Object value);

可能属于ICollection接口。

Interface Segregation Principle - How to decide what to segregate?

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

例如,考虑启动一个设计,将IList方法移入ICollection中,而没有IList子接口。您可以用这两个接口成功地构建ListLinkedList类。

现在考虑在混合物中添加HashSet。这个类必须实现四个与集合不匹配的方法,这意味着您应该考虑添加一个或两个子接口-一个用于列表,另一个用于集合。

在任何类就位之前,很难决定隔离,因为您的接口倾向于满足需要使用它的特定类的需要。通常从平面接口结构开始,然后在后续版本中通过重构进行扩展。