【问题标题】:What should I consider when choosing between chainability and language constructs?在可链接性和语言结构之间进行选择时,我应该考虑什么?
【发布时间】:2009-11-09 17:05:58
【问题描述】:

我很难做出这个设计决定。

我可以使用传统的new语言构造来初始化对象,并通过变量来使用它们,例如:

$o = new Object('arg');
$o->method();
$o->property = 'value';
$o->save();

或者我可以选择工厂模式和积极的可链接性,比如 as

Object::new('arg')->method()->setProperty('value')->save();

这会导致

  • 更少的 LOC 到
    • 阅读,
    • 维护,
    • 重构,
  • 无需命名变量。

但是,我不确定这是否是一种可接受的方法,以及我是否忘记考虑某些因素。

请表达您的担忧或同意,并指导我如何做出决定。

【问题讨论】:

  • 作为记录,虽然我假设您正在寻找与语言无关的答案,但某些语言的风格会暗示一种或另一种选择。我猜这是 Perl 还是 PHP?
  • 是的,我希望会有特定于 PHP 的答案,但与语言无关的建议也会很有帮助。

标签: oop chaining


【解决方案1】:

我对最近流行的 Fluent Interface 有不同的看法。

对我来说,当整个方法链从头到尾表达一个单一的概念时,流畅的接口才有意义。例如:

var SuperLate = (new Coffee()).AddMocha().AddCream().Invert().Blend();

每个步骤都需要链的上下文才能有意义,并且链中方法的执行顺序很重要。如果在 Invert() 之前调用 Blend(),就会出现混乱。

在您的示例中,接口的方法之间几乎没有时间耦合。设置属性和执行方法不应依赖于顺序。我相信为例行方法调用和属性操作引入一个流畅的接口只会增加接口的复杂性,同时给人一种时间耦合的感觉。

另外,添加一个流畅的接口增加了每个方法之间的耦合,因为它们现在相互依赖于彼此的返回值。当每个方法只表达整体概念的一部分时(如制作咖啡的步骤),这种耦合是有意义的,但当每个方法单独存在时,可能会阻碍未来的重构。

虽然它可能更冗长,但我不建议为例程方法调用和属性设置引入流畅的接口。

【讨论】:

  • 我可能没有为这个例子选择最好的例程名称,但我更喜欢配置对象而不是多个 setter 调用。如您所见,该示例还引导对象从初始化到保存。订单独立性是否只会困扰您?
  • 结构的规模让我更加烦恼。我见过的大多数流畅的接口都是由小组件构成的(一个 nHibernate 映射)。小组件并不是真正独立存在的。配置和保存对象不是一个单一的结构。这是一系列谨慎的步骤。这就是为什么我不觉得流畅的界面是合适的。然而,这只是我的看法。
  • 太糟糕了,较新的“OO”语言不支持原始(Smalltalk)所做的交互。在 Smalltalk 中,向一个对象发送多条消息并用分号分隔它们是一件简单的事情。 (长方形新)颜色:红色; addToCanvas: mainCanvas.
  • 我同意大型结构使代码在某些边缘情况下难以维护,但我主要计划在 ORM 和其他基本对象集中实现流畅的接口,这样可能会加快开发速度。不过,谢谢你的相反意见! +1
【解决方案2】:

流畅界面的好处在于,代码的核心不会在额外的语法管道中丢失,使其更易于阅读。然而,与逐行程序方法相比,它是一个不太熟悉的习语,而且没有那么普遍;并非所有代码结构都适合这种风格,例如

if (something) $o->method();

不会翻译得很干净。因此,如果这些事情是典型的,那么它可能并不合适。

还要考虑将围绕它的其他代码的上下文。如果代码将主要是这些样板样板看起来像

$o = new Object('arg');
$o->method();
$o->property = 'value';
$o->save();

然后让它们更简洁肯定是一种改进。但如果这样的代码会在许多其他不同风格的代码中丢失,也许不会。

如果这看起来可能是一个好主意,我会说去吧。如果效果不好,切换回来的小努力将值得学习经验。

【讨论】:

    【解决方案3】:

    我非常喜欢您的“可链式”设计。这种设计有时被称为Fluent Interface

    【讨论】:

    • 很高兴你喜欢它。不过,除了狂热,还有什么可以提及的吗?
    • 我认为您很好地总结了它的好处:由于缺乏明确的本地状态和一般的简短性,更易于阅读/维护/重构。
    【解决方案4】:

    为什么没有多个构造函数来获取初始化值。所以你会:

    Object::new()
    Object::new('arg1')
    Object::new('arg1','arg2')
    

    等等

    【讨论】:

      猜你喜欢
      • 2016-10-13
      • 1970-01-01
      • 2011-02-14
      • 2017-05-17
      • 2011-04-25
      • 1970-01-01
      • 2017-02-16
      • 2010-11-03
      • 1970-01-01
      相关资源
      最近更新 更多