我正在阅读有关PHP 5.4.0中新功能的文章。 其中最令人期待的是Traits。
阅读这些 Traits ,看看它们的全部内容,它们只是看起来像编译器辅助的复制粘贴给我;和一种语言提供了使用组合的方式,非常类似于众所周知的策略模式,它利用了“有利于组合而不是继承”的设计原则。
我是否正确理解了这一点?
这些特性可能带来哪些其他优势,使它们变得有价值,而不仅仅是使用构图设计原则?
答案 0 :(得分:19)
不,由于特征被“粘贴”到一个类中的规则完全不同,因此特征不仅仅是构成。
使用Composition时,不存在冲突或方法覆盖的可能性,因为复合元素是一个完全隔离的单元(某个其他类的实例),它通过消费实例中的公共API与之交互。此外,如果您需要从使用实例提供访问权限,则必须添加代理方法以委派给复合元素。
另一方面,Traits成为它们所使用的实例的API的一部分。它们不是实例中的子系统。它们甚至不是实例,而只是一个可重复使用的样板代码。这提供的一个好处是满足与特征的接口,正如我在Traits in PHP – any real world examples/best practices?
中所示答案 1 :(得分:5)
你必须要小心你给作曲的意义。在更一般的意义上,特征是分解和组合的机制。
特征是一种组合机制,因为它们可以由一个类组成。许多特征实现还允许特征彼此组合。
GoF的口头禅是“赞成合成而不是继承”。
默认情况下,所有基于类的语言都支持继承。对象只能从其类或从其继承链中更高的类中获取行为。当然,你可以通过不同的方式获得相同的结果。例如,您可以创建一个Manager类(例如,LayoutMananager),然后在任何具有可铺设行为/布局特征的类中添加对它的引用,并添加除了调用Manager的方法之外什么都不做的函数
public function doSomething() { return layoutManager.doSomething(); }
特质有利于作文。就那么简单。特征的关键特征是它们生活在类层次结构之外。您可以“获取”可重复使用的行为或特征,而不会来自您的任何超级类别(其他帖子中引入的水平与垂直区别)。这是主要优势。
特征的最大问题是当以你可以直接执行myObject.doSomething()而不是myObject.trait1.doSometing()的方式实现traits时出现冲突(直接或间接如上所述使用layoutManager) 。一旦向类中添加多个特征,就很容易出现冲突。您的实现需要支持别名和覆盖等机制来帮助解决冲突。你得到一些开销。
目前尚不清楚PHP实现是否符合这一点,但是traits也应该不指定任何实例变量,traits提供的方法永远不应该直接访问实例变量。 (来源:Adding Traits to (Statically Typed) Languages,PDF)。这个blog post讨论了这一点。它声称在PHP中,名为trait的结构确实是一个mixin(这是与状态的特征)。 (虽然这是other blog post describe them as stateless)
总而言之,根据特征进行思考可能有助于编写更好的代码。编写特征类以避免实例化也可以有助于更好的代码。这可以从任何依赖项中释放特征,从而可以按任何顺序调用它们。但目前尚不清楚在语言本身中添加特征的概念会有助于提高代码质量。
答案 2 :(得分:2)
特征“组合”(它只是类的方法级别的包含)发生在编译时,而你所谈论的组合是在运行时。
当你做这种构图时,特质已经存在。
由于PHP中的单一继承以及常见的静态实用程序类阻碍了某些设计目标,因此特征提供了另一个方面来塑造您的实现并允许减少代码重复。
答案 3 :(得分:1)
特征是行为的同义词,而不是继承或装饰。 它与策略模式不同,因为您可以定义通用算法,而每个具体策略对象具有不同的算法。 此外,它更像是行为的“水平”继承,而不是具有行为规范的“垂直”继承。
问题很有趣。