正如 the Gang of Four 所著的 设计模式 中所说,
我们应该尽量优先选择组合而不是继承的方式。使用继承和组合都有很多好处。
这个准则的主要意义在于当你本能的使用继承时,试着思考一下组合是否能更好对你的需求建模。
在一些情况下,是这样的。
接下来你或许会想,“那我应该在什么时候使用继承?”
答案依赖于你的问题,当然下面有一些何时继承比组合更好的说明:
- 你的继承表达了 “是一个” 而不是 “有一个” 的关系(例如人类 “是” 动物,而用户 “有” 用户详情)。
- 你可以复用基类的代码(人类可以像动物一样移动)。
- 你想通过修改基类对所有派生类做全局的修改(当动物移动时,修改它们的能量消耗)。
糟糕的:
class Employee { private $name; private $email; public function __construct(string $name, string $email) { $this->name = $name; $this->email = $email; } // ... } // 不好,因为Employees "有" taxdata // 而EmployeeTaxData不是Employee类型的 class EmployeeTaxData extends Employee { private $ssn; private $salary; public function __construct(string $name, string $email, string $ssn, string $salary) { parent::__construct($name, $email); $this->ssn = $ssn; $this->salary = $salary; } // ... }
棒棒哒:
class EmployeeTaxData { private $ssn; private $salary; public function __construct(string $ssn, string $salary) { $this->ssn = $ssn; $this->salary = $salary; } // ... } class Employee { private $name; private $email; private $taxData; public function __construct(string $name, string $email) { $this->name = $name; $this->email = $email; } public function setTaxData(string $ssn, string $salary) { $this->taxData = new EmployeeTaxData($ssn, $salary); } // ... }
避免流式接口
流式接口 是一种面向对象 API 的方法,旨在通过方法链 Method chaining 来提高源代码的可阅读性.
流式接口虽然需要一些上下文,需要经常构建对象,但是这种模式减少了代码的冗余度 (例如: PHPUnit Mock Builder
或 Doctrine Query Builder)
但是同样它也带来了很多麻烦:
- 破坏了封装 Encapsulation
- 破坏了原型 Decorators
- 难以模拟测试 mock
- 使得多次提交的代码难以理解
更多信息可以参考 Marco Pivetta 撰写的关于这个专题的文章blog post
Bad:
class Car { private $make = 'Honda'; private $model = 'Accord'; private $color = 'white'; public function setMake(string $make): self { $this->make = $make; // NOTE: Returning this for chaining return $this; } public function setModel(string $model): self { $this->model = $model; // NOTE: Returning this for chaining return $this; } public function setColor(string $color): self { $this->color = $color; // NOTE: Returning this for chaining return $this; } public function dump(): void { var_dump($this->make, $this->model, $this->color); } } $car = (new Car()) ->setColor('pink') ->setMake('Ford') ->setModel('F-150') ->dump();
内容版权声明:除非注明,否则皆为本站原创文章。