親切


1. 継承を減らし、合成をより多く使用する

#2. 一貫したインターフェイスを避ける

## 3. 最終クラスを使用することをお勧めします

1. 継承を減らし、合成をより多く使用します

前に説明したように、 Gang of Four によるデザイン パターン 継承ではなく合成を優先するように努めるべきだと言えます。継承と合成の両方を使用すると、多くの利点があります。このガイドラインの主なポイントは、直感的に継承を使用するときに、合成がニーズをより適切にモデル化できるかどうかを考えてみることです。場合によっては、これは真実です。

次に考えられるのは、「では、いつ継承を使用すればよいのでしょうか?」ということです。答えは質問によって異なりますが、継承が合成よりも優れている場合の手順をいくつか示します。

継承は、「ある」ではなく「ある」という関係を表します (人間 -> 動物、ユーザー -> ユーザーの詳細)

基本クラスのコードを再利用できます (人間は動物に似ることができます) )

基本クラスを変更して、すべての派生クラスにグローバルな変更を加えたいと考えています (動物が移動するときのエネルギー消費を変更します)

Bad:

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

Good:

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. 一貫性のあるインターフェースを避ける

継続的インターフェース

流暢なインターフェースは API ですオブジェクト指向プログラミングにおけるコードの可読性を向上させるために設計されたデザイン パターン。これはメソッド チェーンに基づいていますメソッド チェーン

コンテキストがある場合、PHPUnit Mock Builder やDoctrine Query Builder では、状況が増えるとコストも高くなります:

いくつかのコンテキスト (多くの場合、ビルダー オブジェクト) が存在する可能性がありますが、このパターンによりコードの冗長性が軽減されます (PHPUnit Mock Builder や Doctrine Query Builder など)。

1. オブジェクトのカプセル化が壊れる

2. デコレータ パターンが壊れる

3. テスト コンポーネントで動作しない 簡単に実行できる

モック

4. 送信につながる

diff は読みにくいです

5. 詳細については、著者 Marco Pivetta の「なぜコヒーレント インターフェイスは悪いのか」を参照してください。 .

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

Good:

 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.クラスを使用するアプリケーションを中断することなくコードを作成できます。

唯一の条件は、クラスがインターフェイスを実装し、他のパブリック メソッドが定義されていないことです。

詳細については、ブログ投稿を参照してください。このトピックについては、Marco Pivetta (Ocramius) によって書かれました。

bad:

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;
    }
}

good:

 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;
    }
}