正如 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();
内容版权声明:除非注明,否则皆为本站原创文章。
