收藏670

阅读33253

更新时间2022-04-13

1. 少用继承多用组合

2. 避免连贯接口

3. 推荐使用 final 类

1. 少用继承多用组合

正如 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);
    }
 
    // ...
}

2. 避免连贯接口

连贯接口Fluent interface是一种 旨在提高面向对象编程时代码可读性的API设计模式,他基于方法链Method chaining

有上下文的地方可以降低代码复杂度,例如PHPUnit Mock Builder 和Doctrine Query Builder ,更多的情况会带来较大代价:

While there can be some contexts, frequently builder objects, where this pattern reduces the verbosity of the code (for example the PHPUnit Mock Builder or the Doctrine Query Builder), more often it comes at some costs:

1. 破坏了 对象封装

2. 破坏了 装饰器模式

3. 在测试组件中不好做mock

4. 导致提交的diff不好阅读

5. 了解更多请阅读 连贯接口为什么不好 ,作者 Marco Pivetta.

坏:

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();

好:

 class Car
{
    private $make = 'Honda';
    private $model = 'Accord';
    private $color = 'white';
 
    public function setMake(string $make): void
    {
        $this->make = $make;
    }
 
    public function setModel(string $model): void
    {
        $this->model = $model;
    }
 
    public function setColor(string $color): void
    {
        $this->color = $color;
    }
 
    public function dump(): void
    {
        var_dump($this->make, $this->model, $this->color);
    }
}
 
$car = new Car();
$car->setColor('pink');
$car->setMake('Ford');
$car->setModel('F-150');
$car->dump();

3. 推荐使用 final 类

能用时尽量使用 final 关键字:

1. 阻止不受控的继承链

2. 鼓励 组合.

3. 鼓励 单一职责模式.

4. 鼓励开发者用你的公开方法而非通过继承类获取受保护方法的访问权限.

5. 使得在不破坏使用你的类的应用的情况下修改代码成为可能.

The only condition is that your class should implement an interface and no other public methods are defined.

For more informations you can read the blog post on this topic written by Marco Pivetta (Ocramius).

坏:

final class Car
{
    private $color;
    
    public function __construct($color)
    {
        $this->color = $color;
    }
    
    /**
     * @return string The color of the vehicle
     */
    public function getColor()
    {
        return $this->color;
    }
}

好:

 interface Vehicle
{
    /**
     * @return string The color of the vehicle
     */
    public function getColor();
}
 
final class Car implements Vehicle
{
    private $color;
    
    public function __construct($color)
    {
        $this->color = $color;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getColor()
    {
        return $this->color;
    }
}

科技资讯

更多

精选课程

更多
前端入门_HTML5
前端入门_HTML5

共29课时

61.7万人学习

CSS视频教程-玉女心经版
CSS视频教程-玉女心经版

共25课时

39.3万人学习

JavaScript极速入门_玉女心经系列
JavaScript极速入门_玉女心经系列

共43课时

71万人学习

独孤九贱(1)_HTML5视频教程
独孤九贱(1)_HTML5视频教程

共25课时

61.6万人学习

独孤九贱(2)_CSS视频教程
独孤九贱(2)_CSS视频教程

共22课时

23万人学习

独孤九贱(3)_JavaScript视频教程
独孤九贱(3)_JavaScript视频教程

共28课时

33.9万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时

125万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号