Da'sBlog

php-interfaces-and-traits

interfaces和traits,超强组合

译者注:
老歪,写的文章特别详细,一句话会说好几遍,语义我删减了点。但尽可能保持原意。
如果你还没有用php的interfaces, 会错过面向对象的强大特性. 在PHP 5.4中Interfaces和traits配合十分强大.
Interfaces不在类中,类必须实现interface里约定的方法.

假设我们有个User的类. Users有个地址,我们把地址通过应用邮件包传给PackageShipper(托运人) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Address {
// ... setters and getters for address fields ...
}
class User {
protected $address;
public function setAddress(Address $address) {
$this->address = $address;
}
public function getAddress() {
return $this->address;
}
// ... other user logic ...
}
class PackageShipper {
public function shipTo(User $user) {
$address = $user->getAddress();
// ... do shipping code using $address ...
}
}

我们的应用愉快的传递包, 直到有一天我们有个需求, Companies(公司) 也需要传递包. 我们创建一个公司类来处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Company {
protected $address;
public function setAddress(Address $address) {
$this->address = $address;
}
public function getAddress() {
return $this->address;
}
// ... other company logic ...
}

现在我们遇到一个问题. PackageShipper只知道处理Users. 我们需要PackageShipper类处理任何地址.

我们可以创建基类(就是基本的类) ,Users 和 Companies 集成它,PackageShipper允许任何来至继承 base 的类. 这么做不令人满意. 从含义上讲, Users 和 Companies 是两个不同实体, 他们没有太多的共性用于base继承. 除了地址其他没有一样的了. 还有一些类或许已经继承了别的类, 因为php是单继承的,我们没办法再继承了.

所以, 我们可以用 interface定义一个PackageShipper处理的 Users 和 Companies公共部分 . 然后, Users 和 Companies继承interface, PackageShipper只需要处理继承接口的对象.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
inteface Addressable {
public function setAddress(Address $address);
public function getAddress();
}
class User implements Addressable {
protected $address;
public function setAddress(Address $address) {
$this->address = $address;
}
public function getAddress() {
return $this->address;
}
// ... other user logic ...
}
class Company implements Addressable {
protected $address;
public function setAddress(Address $address) {
$this->address = $address;
}
public function getAddress() {
return $this->address;
}
// ... other company logic ...
}
class PackageShipper {
public function shipTo(Addressable $entity) {
$address = $entity->getAddress();
// ... do shipping code using $address ...
}
}

一个类可以继承多个不同interfaces, 不同基类可以继承同样的interface.

但是这还是有一个问题. Company和User 用同样代码继承Addressable . 这样太浪费了;只要还有接口约束, 继承来至接口类没必要都一样. 但是, 它们都继承了接口, 我们要复制代码. 如果还要第三个Addressable,同样继承interface, 将会带来更多的重复.

如果你使用PHP 5.3 版本以下, 没办法解决的. 但是如果使用PHP 5.4, 有种新的方式可以解决这种问题: traits.

trait类似于类,因为它们都实现方法和属性。不同的是,类可以实例化,但是trait不能。相反,trait可以添加到类定义,给该类的所有定义的方法和属性定义在trait中

traits就像一个宏一样:在类中使用traits和traits中的代码复制到类是一样的。

用traits,我们可以清除重复的代码 ,保持Addressable接口的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
trait AddressAccessor {
protected $address;
public function setAddress(Address $address) {
$this->address = $address;
}
public function getAddress() {
return $this->address;
}
}
class User implements Addressable {
use AddressAccessor;
// ... other user logic ...
}
class Company implements Addressable {
use AddressAccessor;
// ... other company logic ...

现在,任何类可以通过AddressAccessor trait继承Addressable接口 . 重复的代码都可以移除.

trait本身不继承Addressable. 这就是为什么只有classes 可以继承 interfaces. 注意trait的优先级别要小于类里面的。

Interfaces保证 PHP执行正确的代码. 和traits结合, 定义了一个快速开发的强大工具, 减少重复的代码,更易读,更好维护.

下面是应用的最终代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Address {
// ... setters and getters for address fields ...
}
inteface Addressable {
public function setAddress(Address $address);
public function getAddress();
}
trait AddressAccessor {
protected $address;
public function setAddress(Address $address) {
$this->address = $address;
}
public function getAddress() {
return $this->address;
}
}
class User implements Addressable {
use AddressAccessor;
// ... other user logic ...
}
class Company implements Addressable {
use AddressAccessor;
// ... other company logic ...
}
class PackageShipper {
public function shipTo(Addressable $entity) {
$address = $entity->getAddress();
// ... do shipping code using $address ...
}
}

简单点说,接口用于限制,traits减少重复代码。

原文:
http://blog.everymansoftware.com/2012/09/interfaces-and-traits-powerful-combo.html

坚持原创技术分享,您的支持将鼓励我继续创作!