每个接口的一种方法是否是合理的设计选择?

时间:2015-08-03 18:33:53

标签: c# language-agnostic

使用IAddable,IRemovable,IIndexable这样的接口来支持每个操作是否有意义,或者这种方法最终会导致无法管理的代码?

3 个答案:

答案 0 :(得分:4)

想象一下,你想要实现一个类似于数字集合的NumberBucket排序。

可以创建一个像这样的胖界面:

public interface INumberBucket
{
    void Add(int number);
    void Remove(int number);
}

你可以毫无问题地实现它:

 public class NumberBucket : INumberBucket
{
    public void Add(int number)
    {
        Console.WriteLine($"Adding {number}");
    }

    public void Remove(int number)
    {
        Console.WriteLine($"Removing {number}");
    }
}

但是稍后你决定需要实现一个ReadonlyNumberBucket,其中不能被移除:

public class ReadonlyNumberBucket : INumberBucket
{
    public void Add(int number)
    {
        Console.WriteLine($"Adding {number}");
    }

    public void Remove(int number)
    {
        throw new NotImplementedException();
    }
}

好吧,现在Remove没有逻辑实现,因此您必须将其设为no-op或将其抛出。这违反了Liskov Substitution Principle

如果您对两个重点接口进行了十分转换:IAddableIRemovable,您可能还没有实现IRemovable。这是Interface Segregation Principle的基础。

所以,回答你的问题:是的 - 它 是合理的但是在你看到投资回报之前可能还需要一段时间。就像@PhilipStuyck在评论中所写的那样:

  

[..]问题是这个例子是否适用于你的情况。这个答案中的第一个界面对你来说可能已经足够好了,拆分它可能会过度设计。 Overdesign也是一种代码味道。你必须知道何时应用哪种模式。基于问题中的简短解释我无法分辨。

答案 1 :(得分:0)

这取决于"控制的水平"你有自己的应用程序设计。如果您的商品可能是"可添加"但不是" Devidable",你所说的非常有意义。

但是,如果在您的应用程序域中,所有项目通常都支持您描述的基本操作,请不要将它们移动到单独的界面中。

答案 2 :(得分:0)

我看到一些评论,如果你让接口内的所有方法都可能会破坏Liskov的替换。说实话,甚至微软有时也会违反Liskov替代原则。例如,他们使Array实现IList,即使Array类型不支持此接口上的某些方法(例如,如果将数组转换为IList," Add"方法会抛出类型异常NotSupportedException异常)。

最重要的是:你看到你的方法之间有任何逻辑关系吗?至少他们必须属于某一类别或某物。如果是这样,将它们组合成一个接口。在你的情况下,IAddable和IRemovable对我来说似乎是某种程度上的核心,因为它们都代表了一些类似的东西:一个对象可以从一些篮子中移动(添加或删除)。对我而言,IIndexable似乎是一个奖励"喜欢你可以添加但不是强制性的东西。因此,如果我是您的架构师,我会将IIndexable方法放在一个单独的界面中。

无论如何,如果在不久的将来,一个物体将是可以添加的物体。但不会支持"删除"那么你可以通过将你的界面分成两部分并使我们的旧界面继承它们来轻松解决这个问题:IAddable,IRemovable。我倾向于"隔离"在适当的时刻接口,我不喜欢从我的架构的一开始就拆分我的接口。

所以,请记住:

  • 一开始,当情况需要隔离时,只分离显而易见的然后隔离,或者甚至可以选择为了可读性/框架理解而不分离(因为对于他们来说,微软是这样做的,数组是一种List,这应该是这样的。)

  • 像SOLID这样的模式和原则只是一个非常强大的指导,但规则有时会被打破。记住这一点。