提醒(来自wiki):
接口隔离原则(ISP)声明没有客户端应该 被迫依赖它不使用的方法。
现在看看我的例子。
这是我的可变实体。它是从某个地方编辑的,它能够通过只读界面通知有关更改:
interface ICounter
{
event Action<int> NewNumber;
}
class Counter : ICounter
{
public event Action<int> NewNumber;
int number = 0;
public void IncrementAndSend(int x)
{
number += x;
if (NewNumber != null) NewNumber(number);
}
}
这是使用它的传输层的类。看看两种注射变体(Attach_1
和Attach_2
)以及我的假设如下:
class OneToManyRouter
{
IEnumerable<Counter> _destinations;
public OneToManyRouter(IEnumerable<Counter> destinations)
{
_destinations = destinations;
}
// 1
public void Attach_1(ICounter source)
{
source.NewNumber += (n) =>
{
foreach (var dest in _destinations) dest.IncrementAndSend(n);
};
}
// 2
public void Attach_2(Counter source)
{
source.NewNumber += (n) =>
{
foreach (var dest in _destinations) dest.IncrementAndSend(n);
};
}
}
ICounter
接口过多。答案 0 :(得分:2)
ISP既不是类,也不是对象,而是严格关于接口,特别是关于接口设计。该原则旨在阻止在单个接口中对半相关方法进行分组,以避免用户仅需要这些方法的子集将其余方法实现为空函数(抛出NotImplementedException
或将其保留为空:{ }
)。因此,更容易实现更一致的类并更有效地使用接口。
在您的示例中,您将Counter
类与ICounter
接口组合在一起,其方式与ISP概念没有直接关系:
- ISP是关于真实物体的。您不得对传入参数使用“过多”引用。
醇>
这部分是正确的(如果我正确地解释“过度”的概念)。但是,正如我所提到的,ISP 不关于如何与真实对象进行交互,但如何定义有用的界面。
- ISP是关于课程的。如果您的类已在某处使用完整接口,则无需在特定方法中限制引用类型。在这个例子中,ICounter接口过多。
醇>
这不正确。如果您在具体类而不是在接口上创建依赖项,则该类实现接口的事实并不意味着什么。请记住,通过使组件依赖于合同而不是将来可能会更改的特定实现,接口提供了程序各个部分的分离。通过使用具体课程,您将失去这种好处。而且,这与ISP概念并不完全相关。
- 从SOLID原则来看,这种架构是完全错误的(那么为什么?)。
醇>
从架构的角度强调SOLID原则,我建议依赖ICounter
而不是Counter
,并将IncrementAndSend
作为接口定义的一部分。
答案 1 :(得分:0)
我认为将IncrementAndSend方法添加到接口并使类OneToManyRouter依赖于IEnumerable&lt; ICounter&gt;会更好。 在我看来,这不是ISP违规,因为NewNumber事件操作和IncrementAndSend方法是严格相关的。 希望它可以帮到你。