PHP 代码简洁之道(小结)(10)


正如 the Gang of Four 所著的 设计模式 中所说,
我们应该尽量优先选择组合而不是继承的方式。使用继承和组合都有很多好处。
这个准则的主要意义在于当你本能的使用继承时,试着思考一下组合是否能更好对你的需求建模。
在一些情况下,是这样的。

接下来你或许会想,“那我应该在什么时候使用继承?”
答案依赖于你的问题,当然下面有一些何时继承比组合更好的说明:

  1. 你的继承表达了 “是一个” 而不是 “有一个” 的关系(例如人类 “是” 动物,而用户 “有” 用户详情)。
  2. 你可以复用基类的代码(人类可以像动物一样移动)。
  3. 你想通过修改基类对所有派生类做全局的修改(当动物移动时,修改它们的能量消耗)。

糟糕的:

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)

但是同样它也带来了很多麻烦:

  1. 破坏了封装 Encapsulation
  2. 破坏了原型 Decorators
  3. 难以模拟测试 mock
  4. 使得多次提交的代码难以理解

更多信息可以参考 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();


      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/4018.html