特质不仅仅是组合吗?

28

我在阅读一篇关于 PHP 5.4.0 的新功能的文章时,发现其中最受期待的一个是Traits

仔细研究这些Traits,我发现它们看起来只是编译器辅助的复制粘贴,并且是使用组合的方法,非常类似于广为人知的策略模式,其利用了“优先使用组合而不是继承”的设计原则。

我的理解正确吗?

使用这些trait相对于仅使用组合设计模式提供哪些其他优点使它们值得使用呢?


1
(维基) https://wiki.php.net/rfc/horizontalreuse - Gordon
2
我不得不说,它们对我来说似乎有点毫无意义,我从来没有遇到过一个问题,解决不了它们。 - GordonM
10
“@GordonM:仅使用汇编语言是无法解决任何问题的。” - Mchl
@Mchl,你用汇编语言写代码的速度不可能像用PHP那样快。 - Darius.V
4个回答

25
不,特质并不仅仅是组合,因为将特质“粘贴”到类中的规则完全不同。使用组合时,由于组合元素是完全隔离的单元(另一个类的实例),您通过其公共API与消费实例进行交互。此外,如果您需要从消费实例提供访问权限,则必须添加代理方法来委派给组合元素。而特质则成为其所在实例的API的一部分。它们不是实例的子系统。它们甚至不是实例,只是可重用的样板代码。其中一个好处是,满足具有特质的接口,如我在PHP中的特质-任何真实世界的示例/最佳实践?中所示。

3
相较于将外部实例组合进类中,使用Trait是否更加冒险?Trait代码块(方法?我不知道怎么称呼)与宿主类的方法冲突怎么办?如果将多个Trait导入同一类中,它们之间的代码块会不会冲突?也许我漏掉了什么,但如果不小心使用,Trait似乎很容易变得混乱。 - GordonM
1
@GordonM:你需要按照定义解决冲突,这在PHP手册中有详细说明(Traits Precedence)。当然,和任何语言特性一样,你也可以用traits搞砸事情。 - hakre
好的,我会看一下。然而,我必须说目前为止我不太喜欢这些事情。 - GordonM
在正确的上下文中,它非常有用,但其范围有限,但肯定足够普遍。 - Jason

8

在更广义的意义上,你需要仔细考虑组合所赋予的含义。特征是一种分解和组合的机制,可以用于代码复用(DRY)的适当单元的分解。

  • 分解--如何将软件基础分解为适合我们应用程序领域的类层次结构
  • 组合--如何组合这些单元以获得适合我们应用程序领域的类层次结构。

特征是一种组合机制,可以与类组合使用。许多特性实现也允许对特性进行组合。

GOF的口号是“优先选择组合而非继承”。

所有基于类的语言默认情况下都偏爱继承。对象只能从其类或类继承链中较高的类获取行为。当然,你可以通过不同的方式实现相同的结果。例如,你可以创建一个 Manager 类(例如 LayoutManager),然后将其引用添加到任何具有可放置行为/布局特征的类中,并添加没有其他作用的函数,只需调用管理器的方法即可。

public function doSomething() { return layoutManager.doSomething(); }

特征偏好组合。就这么简单。特征的关键特点是它们存在于类层次结构之外,可以“获取”可重用的行为或特征,而无需来自任何超类(水平与垂直区别在其他帖子中介绍)。这是主要的优点。
特征的最大问题是,当特征以一种你可以直接执行myObject.doSomething()而不是myObject.trait1.doSometing()(直接或间接地与layoutManager描述的方式)实现时,冲突会出现。一旦向类添加多个特征,冲突就很容易出现。您的实现需要支持诸如别名和覆盖等机制,以帮助解决冲突。这会产生一些额外开销。
并不清楚PHP实现是否符合此要求,但是特征也不应指定任何实例变量,特征提供的方法不应直接访问实例变量。(来源:Adding Traits to (Statically Typed) Languages,PDF)。这篇博客文章进行了讨论。它声称在PHP中,名为trait的结构实际上是一个mixin(即具有状态的特征)。 (虽然这其他博客文章将它们描述为无状态
总之,从特征的角度思考可能有助于编写更好的代码。为了写出更好的代码,编写特征类以避免实例化也可能有所贡献。这使特征不受任何依赖关系的限制,使其可以按任何顺序调用。但是并不清楚将特征的概念添加到语言本身是否会有助于编写更好的代码。

2

特征“组合”(它只是类方法级别的包含),发生在编译时,而您谈论的组合是在运行时发生的。

当您进行该组合时,特征已经存在。

由于PHP中的单一继承以及常见的静态实用程序类阻碍了某些设计目标,因此特征提供了另一种方式来塑造您的实现,并允许减少代码重复。


1

特征更像是行为,而不是继承或装饰。

它与策略模式不同,因为您可以定义通用算法,而每个具体的策略对象都有不同的算法。

此外,它更像是一种“水平”的行为继承,而不是具有行为规范的“垂直”继承。

这个问题非常有趣。


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