性状不是简单的组成吗?

2022-08-30 17:13:35

我正在阅读一篇关于PHP 5.4.0中新功能的文章。最受期待的一个是特质

阅读这些特征,看看它们是什么,它们对我来说只是看起来像编译器辅助复制粘贴;以及一种语言提供了使用组合的方式,非常类似于众所周知的策略模式中使用的方法,该模式利用了“偏爱组合而不是继承”的设计原则。

我是否正确理解了这一点?

这些特征可能提供哪些其他优势,使它们值得,而不仅仅是使用组合设计原则?


答案 1

不,特征不仅仅是组合,因为特征被“粘贴”到一个类中的规则是完全不同的。

使用 Composition 时,不会发生冲突或方法覆盖,因为复合元素是一个完全隔离的单元(某个其他类的实例),您从使用实例中通过其公共 API 与之交互。此外,如果需要提供来自使用实例的访问权限,则必须添加代理方法来委派到复合元素。

另一方面,特征成为使用它们的实例的API的一部分。它们不是实例中的子系统。它们甚至不是实例,而只是一个可重用的样板代码。这提供的一个好处是满足具有特征的接口,正如我在PHP中的特征中所示 - 任何现实世界的例子/最佳实践?


答案 2

你必须小心你赋予构图的意义。在更一般的意义上,性状是分解和组成的机制。

  • 分解 - 我们如何将软件库分解为合适的重用单元(代码重用,DRY)。
  • 组合 -- 我们如何组合这些单元以获得适合于我们的应用程序域的类层次结构。

特征是一种组合机制,因为它们可以与类组成。许多特征实现还允许特征彼此组合。

GoF的口头禅是“支持组合而不是继承”。

默认情况下,所有基于类的语言都支持继承。对象只能从其类或继承链中较高级别的类获取行为。当然,您可以通过不同的方式实现相同的结果。例如,您可以创建一个管理器类(例如,LayoutMananager),然后在具有可铺设行为/布局特征的任何类中添加对它的引用,并添加除了调用管理器的方法之外什么都不做的函数。

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

性状有利于构图。就是这么简单。特征的关键特征是它们生活在类层次结构之外。你可以“获取”可重用的行为或特征,而不需要它们来自你的任何超类(其他帖子中引入的水平与垂直区别)。这是主要优势。

特征的最大问题是,当特征以一种可以直接执行myObject.doSomething()而不是myObject.trait1.doSometing()的方式实现时,就会出现冲突(直接或间接地,如上所述, layoutManager)。一旦你向一个类添加了多个特征,冲突就很容易出现。您的实现需要支持别名和覆盖等机制,以帮助解决冲突。你会得到一些开销。

目前尚不清楚PHP实现是否符合这一点,但traits也应该不指定任何实例变量,并且traits提供的方法不应该直接访问实例变量。(来源:将特征添加到(静态类型)语言,PDF)。这篇博客文章讨论了这个问题。它声称在PHP中,名为tratraits的结构实际上是一个mixin(即具有状态的traits)。(尽管这篇其他博客文章将它们描述为无状态)

总而言之,从特征的角度思考可能有助于编写更好的代码。编写 traits 类以避免实例化也有助于改进代码。这将特征从任何依赖关系中解放出来,从而可以按任何顺序调用它们。但目前尚不清楚在语言本身中添加特征的概念是否有助于更好的代码。


推荐