【问题标题】:Why should you strive for more than one interface member whenever possible?为什么要尽可能争取多个界面成员?
【发布时间】:2013-06-20 12:59:57
【问题描述】:

一般来说,为什么要为每个界面争取三到五个成员?

然后,这样的事情有什么问题?

interface IRetrieveClient
{
    Client Execute(string clientId);
}

interface ISaveClient
{
    bool Execute(Client client);
}

interface IDeleteClient
{
    bool Execute(string clientId);
}

当我看到这个时,它会尖叫“反模式!”因为接口没有完成任何事情,尤其是当应用程序的设计者打算让每个接口与实现它的类具有一对一的关系时。

Read:一旦实现了接口,就永远不会再重新实现它。现在,我没有设计这个系统,在我看来他们想要做的是实现某个版本的命令模式,但是在与开发人员交谈时,他们似乎并没有得到它。

【问题讨论】:

  • 为什么要在界面中争取一些成员?以IDisposable 为例
  • 我会说一个界面应该有尽可能多或尽可能少的成员,因为它对您的应用程序设计有意义。在这种情况下,如果您的应用程序设计具有可以为第三方检索/读取或只写的实现,那么它是有意义的。另请注意,您也可以通过这种方式创建组合接口(例如,interface IChangeClient : ISaveClient, IDeleteClienet) 编辑:也就是说,如果您的应用程序设计不需要限制某些实现不能做其中一些事情,那么它可能是将其拆分为 3 个接口不必要的复杂性。
  • IDisposable 完全有意义,命令模式也是如此,但我不知道您为什么不通过具有 get、save 和 delete 成员的 IClient 公开此类内容。
  • 在这种情况下,您似乎可以轻松拥有一个界面,因为它不会违反 SRP(请参阅我的回答)。但是只有一种方法对我来说似乎没有任何问题或“反模式”
  • 您应该阅读 SOLID 原则中的接口隔离原则。最好的解释这一点。

标签: c# architecture interface interface-design


【解决方案1】:

我非常广泛地使用单方法每个接口模式的一个领域是泛型以及一些泛型调度基础架构。

例如:

public interface IValidateEntities<T>
{
    bool Validate(T entity);
}

然后当需要对某种类型的实体做某事时,我们可以使用反射来找出调用哪个实现(反射的结果通常会提前缓存)。

我不久前就这种模式做了一个演示,可以在这里查看:

http://www.infoq.com/presentations/Making-Roles-Explicit-Udi-Dahan

【讨论】:

  • 喜欢那个演示文稿。尤其是使用反射,您有时甚至可以在没有单一方法的情况下拥有一个接口,这样您就有了一些标记。当然,您也可以就约定达成一致,以便命名提供相同类型的“标记”。就像 NServiceBus 在不显眼的模式下处理消息一样。
【解决方案2】:

这在我看来完全合理。我很高兴每个接口有少量方法(或实际上是一种方法)。

请注意,组合接口的好处是您可以(比如说)通过适当的强制转换来选择性地呈现一个类的不同视图。例如您可以构造/修改一个类,然后通过更受限制的接口(例如,具有只读接口)呈现它(缩小它)

例如

interface Readable {
   Entity get();
}

interface Writeable {
   void set(Entity e);
}

一个类可以实现这两个接口,这样您就可以对其进行变异,然后您可以将其简单地作为Readable 对象呈现给客户,这样他们就无法对其进行变异。由于细分了接口,这是可能的。

【讨论】:

    【解决方案3】:

    您应该小心使用一般规则并过于严格地应用它们。如果您需要的话,您的方法本身没有问题。

    但您可能想考虑以下替代方案:

    interface IClient
    {
         Client Retrieve(string clientId);
         bool Save(Client client);
         bool Delete(string clientId);
    }
    

    这种方式的好处是,当你使用注入的时候,你只需要注册一个实例,你的构造函数中只有一个接口。

    因此,如果它在逻辑上属于一起,我会将其保留在一个界面中,因为它可以减少混乱并且不那么复杂。

    【讨论】:

      【解决方案4】:

      设计中重要的一点是要遵守 Robert Martin 所说的单一责任原则。在您的情况下,我认为 L-Three 提出的建议是非常合理的,因为客户将承担一项责任 - 与数据库(或服务等)交谈。因此,如果您看到 IClient 中的方法由于某种原因会变得完全不同并且破坏了 SRP,那么您可以将它拆分为多个接口,我认为如果一个接口只有一个方法,这不是问题。例如,一个很好的例子是一个名为IKeyGenerator 的接口,它以线程安全的方式生成密钥。该接口只有GetNextKey() 方法,这已经足够了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-14
        • 1970-01-01
        • 1970-01-01
        • 2014-02-20
        • 2011-04-06
        相关资源
        最近更新 更多