SOLID Principes des cours SOLID



1. S : Principe de responsabilité unique (SRP)

2. O : Principe ouvert/fermé (OCP)

3.

4. I : Principe de ségrégation d'interface (ISP)

5. D : Principe d'inversion de dépendance (DIP)

SOLID

SOLID est un acronyme facile à retenir recommandé. par Michael Feathers, qui représente les cinq principes de conception de codage orientés objet les plus importants nommés par Robert Martin

  • SOLID 是Michael Feathers推荐的便于记忆的首字母简写,它代表了Robert Martin命名的最重要的五个面对对象编码设计原则

    • S: 单一职责原则 (SRP)

    • O: 开闭原则 (OCP)

    • L: 里氏替换原则 (LSP)

    • I: 接口隔离原则 (ISP)

    • D: 依赖倒置原则 (DIP)

    1. 单一职责原则

    Single Responsibility Principle (SRP)

    正如在Clean Code所述,"修改一个类应该只为一个理由"。 人们总是易于用一堆方法塞满一个类,如同我们只能在飞机上 只能携带一个行李箱(把所有的东西都塞到箱子里)。这样做 的问题是:从概念上这样的类不是高内聚的,并且留下了很多 理由去修改它。将你需要修改类的次数降低到最小很重要。 这是因为,当有很多方法在类中时,修改其中一处,你很难知 晓在代码库中哪些依赖的模块会被影响到。

    坏:

    class UserSettings
    {
        private $user;
     
        public function __construct(User $user)
        {
            $this->user = $user;
        }
     
        public function changeSettings(array $settings): void
        {
            if ($this->verifyCredentials()) {
                // ...
            }
        }
     
        private function verifyCredentials(): bool
        {
            // ...
        }
    }

    好:

    class UserAuth
    {
        private $user;
     
        public function __construct(User $user)
        {
            $this->user = $user;
        }
        
        public function verifyCredentials(): bool
        {
            // ...
        }
    }
     
    class UserSettings
    {
        private $user;
        private $auth;
     
        public function __construct(User $user)
        {
            $this->user = $user;
            $this->auth = new UserAuth($user);
        }
     
        public function changeSettings(array $settings): void
        {
            if ($this->auth->verifyCredentials()) {
                // ...
            }
        }
    }

    2. 开闭原则

    Open/Closed Principle (OCP)

    正如Bertrand Meyer所述,"软件的工件( classes, modules, functions 等) 应该对扩展开放,对修改关闭。" 然而这句话意味着什么呢?这个原则大体上表示你 应该允许在不改变已有代码的情况下增加新的功能

    坏:

    abstract class Adapter
    {
        protected $name;
     
        public function getName(): string
        {
            return $this->name;
        }
    }
     
    class AjaxAdapter extends Adapter
    {
        public function __construct()
        {
            parent::__construct();
     
            $this->name = 'ajaxAdapter';
        }
    }
     
    class NodeAdapter extends Adapter
    {
        public function __construct()
        {
            parent::__construct();
     
            $this->name = 'nodeAdapter';
        }
    }
     
    class HttpRequester
    {
        private $adapter;
     
        public function __construct(Adapter $adapter)
        {
            $this->adapter = $adapter;
        }
     
        public function fetch(string $url): Promise
        {
            $adapterName = $this->adapter->getName();
     
            if ($adapterName === 'ajaxAdapter') {
                return $this->makeAjaxCall($url);
            } elseif ($adapterName === 'httpNodeAdapter') {
                return $this->makeHttpCall($url);
            }
        }
     
        private function makeAjaxCall(string $url): Promise
        {
            // request and return promise
        }
     
        private function makeHttpCall(string $url): Promise
        {
            // request and return promise
        }
    }

    好:

    interface Adapter
    {
        public function request(string $url): Promise;
    }
     
    class AjaxAdapter implements Adapter
    {
        public function request(string $url): Promise
        {
            // request and return promise
        }
    }
     
    class NodeAdapter implements Adapter
    {
        public function request(string $url): Promise
        {
            // request and return promise
        }
    }
     
    class HttpRequester
    {
        private $adapter;
     
        public function __construct(Adapter $adapter)
        {
            $this->adapter = $adapter;
        }
     
        public function fetch(string $url): Promise
        {
            return $this->adapter->request($url);
        }
    }

     

    3. 里氏替换原则

    Liskov Substitution Principle (LSP)S : Principe de responsabilité unique (SRP)

    < /li>
  • O : Principe ouvert-fermé (OCP)

  • 🎜L : Principe de substitution de Liskov (LSP)🎜
  • 🎜I : Principe de séparation d'interface (ISP) 🎜
  • 🎜D : Principe d'inversion de dépendance (DIP)🎜
🎜🎜 1. Principe de responsabilité unique🎜🎜Principe de responsabilité unique ( SRP)🎜🎜Comme indiqué dans Clean Code, "La modification d'une classe ne doit avoir lieu que pour une seule raison." Il est toujours facile de remplir une classe avec un tas de méthodes, tout comme on ne peut transporter qu'une seule valise dans l'avion (tout mettre dans la valise). Le problème est que, conceptuellement, une telle classe n’est pas très cohérente et laisse de nombreuses raisons de la modifier. Il est important de minimiser le nombre de fois où vous devez modifier une classe. En effet, lorsqu'il y a plusieurs méthodes dans une classe, si vous en modifiez une, il est difficile de savoir quels modules dépendants dans la base de code seront affectés. 🎜🎜Mauvais :🎜
class Rectangle
{
    protected $width = 0;
    protected $height = 0;
 
    public function setWidth(int $width): void
    {
        $this->width = $width;
    }
 
    public function setHeight(int $height): void
    {
        $this->height = $height;
    }
 
    public function getArea(): int
    {
        return $this->width * $this->height;
    }
}
 
class Square extends Rectangle
{
    public function setWidth(int $width): void
    {
        $this->width = $this->height = $width;
    }
 
    public function setHeight(int $height): void
    {
        $this->width = $this->height = $height;
    }
}
 
function printArea(Rectangle $rectangle): void
{
    $rectangle->setWidth(4);
    $rectangle->setHeight(5);
 
    // BAD: Will return 25 for Square. Should be 20.
    echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL;
}
 
$rectangles = [new Rectangle(), new Square()];
 
foreach ($rectangles as $rectangle) {
    printArea($rectangle);
}
🎜Bon :🎜
interface Shape
{
    public function getArea(): int;
}
 
class Rectangle implements Shape
{
    private $width = 0;
    private $height = 0;
 
    public function __construct(int $width, int $height)
    {
        $this->width = $width;
        $this->height = $height;
    }
 
    public function getArea(): int
    {
        return $this->width * $this->height;
    }
}
 
class Square implements Shape
{
    private $length = 0;
 
    public function __construct(int $length)
    {
        $this->length = $length;
    }
 
    public function getArea(): int
    {
        return $this->length ** 2;
    }
}
 
function printArea(Shape $shape): void
{
    echo sprintf('%s has area %d.', get_class($shape), $shape->getArea()).PHP_EOL;
}
 
$shapes = [new Rectangle(4, 5), new Square(5)];
 
foreach ($shapes as $shape) {
    printArea($shape);
}
🎜
🎜2. Principe ouvert/fermé🎜🎜🎜Ouvert/fermé Principe (OCP)🎜🎜Comme l'a dit Bertrand Meyer, "Les artefacts du logiciel ( classes, modules, fonctions, etc.) doivent être ouverts pour extension et fermés pour modification." la phrase veut dire quoi ? Ce principe signifie généralement que vous devez autoriser l'ajout de nouvelles fonctionnalités sans modifier le code existant 🎜🎜Mauvais :🎜
interface Employee
{
    public function work(): void;
 
    public function eat(): void;
}
 
class HumanEmployee implements Employee
{
    public function work(): void
    {
        // ....working
    }
 
    public function eat(): void
    {
        // ...... eating in lunch break
    }
}
 
class RobotEmployee implements Employee
{
    public function work(): void
    {
        //.... working much more
    }
 
    public function eat(): void
    {
        //.... robot can't eat, but it must implement this method
    }
}
🎜Bon :🎜
interface Workable
{
    public function work(): void;
}
 
interface Feedable
{
    public function eat(): void;
}
 
interface Employee extends Feedable, Workable
{
}
 
class HumanEmployee implements Employee
{
    public function work(): void
    {
        // ....working
    }
 
    public function eat(): void
    {
        //.... eating in lunch break
    }
}
 
// robot can only work
class RobotEmployee implements Workable
{
    public function work(): void
    {
        // ....working
    }
}
🎜 🎜🎜< a name=" 3">🎜3. Principe de substitution de Liskov🎜🎜Principe de substitution de Liskov (LSP)🎜🎜C'est un principe simple, mais il utilise un terme difficile à comprendre. Sa définition formelle est « Si S est un sous-type de T, alors tout objet de type T peut être remplacé par un objet de type S sans modifier les propriétés initialement établies du programme (vérification, exécution de tâches, etc.) (par exemple, Utiliser un objet de S peut remplacer un objet de T)" Cette définition est plus difficile à comprendre :-). 🎜

La meilleure explication de ce concept est la suivante : si vous avez une classe parent et une classe enfant, la classe parent et la classe enfant peuvent être interchangées sans changer l'exactitude du résultat original. Cela semble encore un peu déroutant, alors regardons un exemple classique carré-rectangle. Mathématiquement, un carré est un rectangle, mais ce n'est pas vrai lorsque votre modèle utilise une relation « est-un » par héritage.

Mauvais:

class Employee
{
    public function work(): void
    {
        // ....working
    }
}
 
class Robot extends Employee
{
    public function work(): void
    {
        //.... working much more
    }
}
 
class Manager
{
    private $employee;
 
    public function __construct(Employee $employee)
    {
        $this->employee = $employee;
    }
 
    public function manage(): void
    {
        $this->employee->work();
    }
}

Bon:

Il serait préférable de traiter ces deux types de quads séparément et de les remplacer par un sous-type plus général qui correspond aux deux types.

Bien que les carrés et les rectangles se ressemblent, ils sont différents. Un carré est plus proche d’un losange, tandis qu’un rectangle est plus proche d’un parallélogramme. Mais ce ne sont pas des sous-types. Bien que semblables, les carrés, les rectangles, les losanges et les parallélogrammes sont tous des formes différentes possédant leurs propres propriétés.

interface Employee
{
    public function work(): void;
}
 
class Human implements Employee
{
    public function work(): void
    {
        // ....working
    }
}
 
class Robot implements Employee
{
    public function work(): void
    {
        //.... working much more
    }
}
 
class Manager
{
    private $employee;
 
    public function __construct(Employee $employee)
    {
        $this->employee = $employee;
    }
 
    public function manage(): void
    {
        $this->employee->work();
    }
}

4. Principe de ségrégation des interfaces

Principe de ségrégation des interfaces (ISP)Interface Segregation Principle (ISP)

接口隔离原则表示:"调用方不应该被强制依赖于他不需要的接口"

有一个清晰的例子来说明示范这条原则。当一个类需要一个大量的设置项, 为了方便不会要求调用方去设置大量的选项,因为在通常他们不需要所有的 设置项。使设置项可选有助于我们避免产生"胖接口"

坏:

rrreee

好:

不是每一个工人都是雇员,但是每一个雇员都是一个工人

rrreee

5. 依赖倒置原则

Dependency Inversion Principle (DIP)

Le principe de ségrégation des interfaces signifie : "L'appelant ne doit pas être obligé de s'appuyer sur des interfaces dont il n'a pas besoin"

Oui Un exemple clair démontre ce principe. Lorsqu'une classe nécessite un grand nombre de paramètres, il est pratique de ne pas demander à l'appelant de définir un grand nombre d'options, car il n'a généralement pas besoin de tous les paramètres. Rendre les paramètres facultatifs nous aide à éviter les « grosses interfaces » 5. Principe d'inversion de dépendance

Principe d'inversion de dépendance (DIP)

Ce principe illustre deux points fondamentaux :

Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau, ils doivent tous dépendre de abstractions

Les résumés ne devraient pas dépendre des implémentations, les implémentations devraient dépendre des abstractions

Cela peut sembler un peu obscur au début, mais si vous avez utilisé des frameworks PHP (tels que Symfony), vous devriez rencontrer l'injection de dépendances (DI), qui est une mise en œuvre de ce concept. Bien qu'il ne s'agisse pas de concepts exactement équivalents, le principe d'inversion de dépendance sépare les détails d'implémentation et la création de modules d'ordre supérieur des modules d'ordre inférieur. Ceci peut être réalisé en utilisant l’injection de dépendances (DI). Le plus grand avantage est qu’il dissocie les modules les uns des autres. Le couplage rend la refactorisation difficile et constitue un très mauvais modèle de développement.

Mauvais :

rrreee

Bon :

rrreee🎜🎜🎜🎜 🎜