跳至正文
来自: 首页 » Coder Life » PHP: HyperText Preprocessor » 代码的组合与继承

代码的组合与继承

一般来说,代码的复用有“组合”与“继承”两种方式,我们更推荐使用组合的方式,它为我们带来了更大的灵活性。而继承,应当是“组合的一种组合方式”,只有特定组合的组合方式多次产生时,才应该用基类的方式将它固化下来。

在 PHP 中,我们一般使用 Trait 来实现组合,通过抽象类、接口类或基类的方式来实现继承。

一、组合——更灵活的代码复用方式

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。

php.net

道丁快搜中,大量使用了 Trait 机制。

我们可以根据一些类具有的某种相同“特征”,抽象出一些公共的方法、属性。

这些公共代码可以放在一个集合中,这个集合就叫做 Trait。

组合,为我们带来了更大的灵活性

我们可以在一个类中,通过引入 A Trait,获得鉴权的逻辑;在另一个类中,通过引入 A 和 B 两个 Trait,兼得 Redis 连接池和 Http 请求的通用方法。

在使用组合达到编码快感的同时,大量的 Trait 也为我们带来了很多的麻烦:

  • 因为 Trait 组合是同级的,不存在继承。大量的 Trait 堆积在我们面前的时候,我们常常无法快速准确地找到目标,对刚接触项目的新同学来说尤其如此。
  • 虽然 Trait 之间没有继承与多态,但是不同的 Trait 却可能产生重复的组合。比如鉴权 trait 已经组合了 Redis Trait,但开发者在不清楚黑盒逻辑的情况下,就会很轻易地产生问题。

二、继承——组合的组合

经过第一节的论述,我们意识到毫无克制地使用 Trait,也会对我们造成很多困扰。

混乱,就需要断舍离。

我们需要某种规则进行整理。

我们将这一节定得比较绕的标题,抽象成比较简单的数学模型:

\[BaseClass=\sum_{i=0}^n Trait_n\]

别慌,我来解释下。先解释下各个符号的意义:

  • BaseClass 代表一个基类。这里特指一个适用于某种特定场合、具有某种特征的基类
  • Trait 代表一个PHP中的 trait,直译过来叫“特征”,是 PHP5 之后的一个新特性。
  • ∑ 读作“西格玛(sigma)”,是求和的意思,相当于一个 for 循环。i=0 是初始值,最大到 n。

上面的公式用 PHP 代码表示出来就很直观了:

$abstract_class = [];

for($i=0; $i<=n; $i++) {
  $abstract_class[] = $trait[$i];
}

(这里感慨下数学之美,五行代码表达出来的东西,用数学建模只用一行)

从上面的讨论过程可以得出以下定义:

这条结论我们暂且将它定为一个公理,后续我们会依赖这条定义来讨论。

标签:

发表回复

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据