【问题标题】:What are the advantages of using a concept like IStartable?使用像 IStartable 这样的概念有什么好处?
【发布时间】:2009-05-26 04:32:39
【问题描述】:

而不是使用这样的接口:

public interface IStartable
{
    void Start();
    void Stop();
}

我通常只是让对象的构造函数运行 Start() 代码,并实现 IDisposable 以便 dispose 方法运行 Stop() 代码。

这只是风格问题吗?还是因为没有像 IStartable 这样的东西而错过了一些重要的东西?我所看到的只是额外的复杂性,因为您必须保持它的启动/停止状态。

使用 start/stop 与使用 ctor/dispose 的优缺点是什么,尤其是在 IoC/DI 容器的上下文中?

编辑:很好的答案,您已经说服我使用可启动对象的接口。我无法决定谁的答案最好,所以我会在 24 小时后接受投票最多的人。

【问题讨论】:

    标签: oop dependency-injection inversion-of-control object-lifetime


    【解决方案1】:

    使用界面的一般优势是它们可以自我描述和自我宣传。如果没有接口,你就没有办法问一个对象,“你能不能启动和停止?”相反,如果您确实使用接口,则可以查询对象以查看它们中的哪些将响应这些类型的消息。那么就可以放心的保证这些对象已经实现了接口封装的功能。

    【讨论】:

    • 这确实是一个大专家,你如何管理它增加的复杂性?您是否担心多次启动,或者在对象停止后能够再次启动?
    • 我不会说它一定会增加任何复杂性。毕竟,您已经不得不以一种或另一种方式编写实现。现在您只是声明它符合某些外部接口。至于您的第二个问题,界面必须定义有关此的规则。符合要求的实现应符合所描述的任何标准。例如,如果您是 IEquatable,则您的 Equals 实现必须保证与空对象的比较始终产生 false。
    • 但是在构造函数中“启动”给你买的一件事是启动方法不能被调用两次,你不必担心重新启动的可能性。是否可以说一个接口具有多次启动的“未定义”行为?还是重新开始?或者最好有一些助手为无效状态更改抛出异常,以便只允许 Initialized -> Started -> Stopped,而其他转换会抛出?
    • 为什么不要求 Start 实现是幂等的,就像汽车点火一样?如果您已经开始,则在您再次停止之前不会发生任何其他事情。
    • 你是说如果你停止一个对象然后你可以重新启动它,还是取决于对象/合同?
    【解决方案2】:

    一般来说,构造函数应该产生一个正确初始化的对象

    仅此而已!

    【讨论】:

    • 在这种情况下不能“正确初始化”意味着启动?或者你是说构造函数不应该有副作用?如果你抱着这个想法跑,你会说连订阅事件都太过分了吗?
    • 构造函数不应该有副作用,它们不应该执行大量计算,除了分配和初始化内存之外它们不应该做任何事情。我绝对不会订阅事件。部分问题(至少在 .NET 中)是取消订阅(或停止)逻辑上属于 dispose 或 finalize 方法,并且它们并不总是在您认为它们会被调用时立即被调用
    • plus 接口使协议更加明确,就像 John 说的那样
    【解决方案3】:

    这可能取决于您说 Start() 时的具体含义。但总的来说,将对象初始化与例程执行(尤其是有状态和/或长时间运行的执行!)混合在一起违反SoC

    它也留下了很大的歧义。对于消费者来说,对于给定的对象,当我们调用 ctor 时,我们如何知道它正在“开始”? “对于这个不执行契约的给定对象,我必须让作者希望它符合我的期望”?接口明确了操作的存在和可用性。

    【讨论】:

      猜你喜欢
      • 2023-01-30
      • 2017-09-14
      • 1970-01-01
      • 1970-01-01
      • 2014-04-06
      • 1970-01-01
      • 2011-06-18
      • 1970-01-01
      • 2019-12-20
      相关资源
      最近更新 更多