接口隔离原则是关于类还是对象的?

4

提醒(来自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_1Attach_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);
        };
    }
}
  1. ISP关注的是真实对象。您不应该使用“过多”的引用传入参数。
  2. ISP关注的是类。如果您的类已经在某个地方使用了完整接口,则无需在特定方法中限制引用类型。ICounter接口在此示例中是过度的。
  3. 从SOLID原则的角度来看,这种架构完全错误(那为什么呢?)。
2个回答

2
ISP并不是关于类或对象,而是严格关于接口设计。该原则旨在防止将半相关的方法分组到单个接口中,以避免用户仅需要子集方法来实现其余为空函数(抛出NotImplementedException或字面意义上为空:{ })。因此,这使得在实现更一致的类和更有效地使用接口都更容易。
在您的示例中,您将Counter类与ICounter接口结合使用,但这种方式并不直接涉及ISP概念:
ISP涉及真正的对象。您不应“过度”引用传入参数。
这部分是正确的(如果我正确解释了“过度”概念)。然而,正如我之前提到的,ISP不是关于如何与真实对象交互,而是关于如何定义有用的接口。
ISP涉及类。如果您的类已经在某个地方使用了完整的接口,则没有必要在特定方法中限制引用类型。在此示例中,ICounter接口是多余的。
这是不正确的。类实现接口并不意味着任何事情,如果您在具体类而不是接口上创建依赖,则会失去接口提供的解耦程序各部分的好处。接口通过使组件依赖于契约而不是可能在未来发生更改的特定实现来解耦。再次,这与ISP概念并不完全相关。
从SOLID原则的角度来看,建议将依赖项放在ICounter而不是Counter上,并将IncrementAndSend作为接口定义的一部分。从架构的角度来看,这种构建方式完全错误(那么为什么?)。

0
我认为将IncrementAndSend方法添加到接口中,并使OneToManyRouter类依赖于IEnumerable 会更好。在我的观点中,这不是ISP违规,因为NewNumber事件操作和IncrementAndSend方法是严格相关的。希望能对您有所帮助。

我不理解什么是严格关系。为什么它很重要?我经常遇到没有相关成员的类... - astef
“严格关系”在接口方法之间的重要性在于允许实现接口的具体类定义具体方法,而不是空的或未实现的方法。这意味着您使用接口定义的角色在对象域中是明确定义和有用的。 - Paolo Laurenti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接