From 71f47b847c0c381dfdeabf5bef2c4c537d568f96 Mon Sep 17 00:00:00 2001 From: Anthony Borghi <anthony.borghi@veremes.com> Date: Fri, 7 Jul 2023 08:51:25 +0200 Subject: [PATCH] design pattern v1 --- source/concept/poo/general.md | 478 +++++++++++++++++++++++++++++++++- 1 file changed, 472 insertions(+), 6 deletions(-) diff --git a/source/concept/poo/general.md b/source/concept/poo/general.md index ef9dfe2..4de1ee1 100644 --- a/source/concept/poo/general.md +++ b/source/concept/poo/general.md @@ -43,7 +43,7 @@ class XWing { } public function shoot() : int { - if ($this->weapon) { + if ($this->hasWeapons) { error_log($this->owner ' tire sur l\'ennemi'); } else { error_log($this->owner ' ne peux pas tirer'); @@ -103,9 +103,26 @@ Ces éléments et leurs intéractions peuvent être modéliser sur un diagramme ### Héritage +Tous les controllers héritent directement ou indirectement de VitisAbstractController. + +Ce qui vous permet de facilement accéder aux services principaux de l'application : +- Accés au disque +- Accés à la base de donnée +- Utilisation des properties +- Configuration de la route +- Gestion des logs +- ... + ### Implémentation -### Traits +L'implémentation est utilisé à plusieurs endroit dans l'application. + +Prenons l'exemple du service d'accés à la base de donnée, ils implémentent tous l'interface DataAccessor. +Vous avez donc la possibilité d'appeler les mêmes méthode sur toutes ces classes, avec les même paramètre et avec le même type de retour. + +Biensûr en cas d'un typage large du retour le comportement ne pourra pas être stable, il faut donc utiliser un typage fort sur ce genre de méthode de développement. + +L'avantage de ce genre de pratique, si dans le futur Vitis doit par exemple se connecter à un nouveau SGBD (mysql par exemple), il suffira de développer un MsqlAccessor qui implémentera DataAccessor, pour que toute l'application fonctionne sans modification. A condition de ne pas avoir utiliser des requêtes SQL directement dans le code via la connexion de DBAL. ### Utilisation de l'interface de manipulation des fichiers @@ -115,13 +132,462 @@ A partir du moment ou votre controlleur hérite de `VitisAbstractController`, il Le FileManager a une relation de composition avec l'une des deux classes ou les deux classes implémentant L'interface `FileAccessorInterface`, à savoir `LocalAccessor` et `S3Accessor`. La nuance d'une ou deux étant compliqué je rentre pas dans le détail. -Le Filemanager se comporte alors comme une **Factory Method** (on en parlera plus tard), qui va fournir l'objet que l'on veut en fonction de la configuration de Vitis. Cette classe va agir comme une couche d'abstraction pour le développeur, c'est à dire qu'il passera le chemin d'écriture et le code lui retournera l'objet adapté pour interagir avec le systéme de fichier utilisé par Vitis. +Le Filemanager se comporte alors comme une **Factory Method** mais en version simplifiée, qui va fournir l'objet que l'on veut en fonction de la configuration de Vitis. Cette classe va agir comme une couche d'abstraction pour le développeur, c'est à dire qu'il passera le chemin d'écriture et le code lui retournera l'objet adapté pour interagir avec le systéme de fichier utilisé par Vitis. ## Autres mot clés -final +- **final** : Signifie que les enfant héritant de cette classe ne pourront pas surcharger cette fonction. +- **self** : Permet d'accéder au constante ou méthode statique d'un objet sans l'instancier. +- **static** : Permet de définir qu'une méthode peut être utiliser sans instanciation de sa classe, c'est à dire qu'elle ne doit pas utiliser **this** pour fonctionner. C'est un usage qui tombe de plus en plus dans l'oubli, cependant il reste utile. Autre utilisation de ce mot clé en PHP, il permet d'utiliser la valeur d'une constante surcharger dans l'enfant depuis un parent. + +## Design Pattern + +Un design pattern, également connu sous le nom de patron de conception, est une solution éprouvée et réutilisable à un problème courant dans la conception de logiciels. Il s'agit d'un modèle de conception générique qui peut être appliqué à différentes situations pour résoudre des problèmes similaires. + +Les design patterns fournissent des approches structurées et éprouvées pour résoudre des problèmes de conception logicielle tels que la création d'objets, la gestion des relations entre les objets, la réutilisation de code, l'organisation du flux d'exécution, etc. Ils permettent de capturer l'expertise et l'expérience des développeurs dans un format réutilisable, favorisant ainsi la clarté, la maintenabilité et l'évolutivité du code. + +Les design patterns ne sont pas des morceaux de code prêts à l'emploi, mais plutôt des modèles conceptuels qui décrivent comment résoudre un problème de conception spécifique. Ils fournissent des directives générales, des structures et des interactions entre les composants logiciels, permettant aux développeurs de créer des solutions flexibles, évolutives et robustes. + +Il existe de nombreux types de design patterns, tels que les patterns de création, les patterns structurels et les patterns comportementaux, chacun se concentrant sur des aspects spécifiques de la conception logicielle. + +On peut aussi s'en inspiré sans forcément les utilisés de manière brut. + +### Patterns de création + +Il se concentre sur les mécanismes de création d'objets en encapsulant le processus de création et en fournissant une interface générique pour créer différents types d'objets. + +Les patterns de création visent à fournir des approches flexibles et modulaires pour créer des objets, en évitant les dépendances directes entre les classes et en améliorant la maintenabilité, la réutilisabilité et la souplesse du code. + +Les patterns de création résolvent généralement des problèmes tels que : +- Comment créer des objets sans couplage étroit avec les classes concrètes. +- Comment configurer et initialiser des objets complexes. +- Comment éviter la duplication de code lors de la création d'objets similaires. +- Comment cacher les détails de création d'objets aux clients. + +Il existe plusieurs patterns de création couramment utilisés, tels que : +- Singleton : garantit qu'une classe n'a qu'une seule instance et fournit un point d'accès global à cette instance. +```php +class Singleton { + private static $instance; + + private function __construct() { + // Constructeur privé pour empêcher l'instanciation directe depuis l'extérieur de la classe + } + + public static function getInstance() { + if (self::$instance === null) { + self::$instance = new Singleton(); + } + return self::$instance; + } +} +``` +- Factory Method : définit une interface pour créer des objets, mais permet aux sous-classes de décider quelle classe concrète instancier. +```php +interface Animal { + public function makeSound(); +} + +class Dog implements Animal { + public function makeSound() { + echo "Woof!"; + } +} + +class Cat implements Animal { + public function makeSound() { + echo "Meow!"; + } +} + +interface AnimalFactory { + public function createAnimal(); +} + +class DogFactory implements AnimalFactory { + public function createAnimal() { + return new Dog(); + } +} + +class CatFactory implements AnimalFactory { + public function createAnimal() { + return new Cat(); + } +} +``` +- Abstract Factory : fournit une interface pour créer des familles d'objets liés ou dépendants sans spécifier leurs classes concrètes. +- Builder : permet de construire un objet complexe étape par étape, en séparant le processus de construction de la représentation finale de l'objet. +- Prototype : permet de créer de nouvelles instances en clonant des objets existants, évitant ainsi les coûts de création d'objets à partir de zéro. + + +### Patterns structurels + +Les patterns structurels sont axés sur l'organisation des objets en utilisant l'héritage, la composition et l'agrégation pour atteindre un certain objectif. Ils permettent de créer des structures plus grandes à partir de petites classes et d'établir des relations entre les objets de manière à simplifier le système global. + +Les patterns structurels sont souvent utilisés pour résoudre des problèmes liés à la composition d'objets, à la réutilisation du code et à l'optimisation des performances. Ils aident à simplifier les interactions entre les objets, à rendre le code plus flexible et maintenable, et à favoriser une meilleure séparation des responsabilités. + +Ces patterns structurels offrent des solutions génériques aux problèmes de structure et d'organisation des objets dans un système. Ils favorisent une meilleure conception logicielle en favorisant la modularité, la flexibilité et la réutilisabilité du code. + +Certains exemples de patterns structurels couramment utilisés sont : + +- Adapter : permet d'adapter une interface existante à une autre interface attendue par le client. +```php +interface MediaPlayer { + public function play($fileName); +} + +interface AdvancedMediaPlayer { + public function playMp4($fileName); + public function playAvi($fileName); +} + +class Mp4Player implements AdvancedMediaPlayer { + public function playMp4($fileName) { + echo "Playing MP4 file: " . $fileName . "<br>"; + } + + public function playAvi($fileName) { + // Ne fait rien + } +} + +class AviPlayer implements AdvancedMediaPlayer { + public function playMp4($fileName) { + // Ne fait rien + } + + public function playAvi($fileName) { + echo "Playing AVI file: " . $fileName . "<br>"; + } +} + +class MediaAdapter implements MediaPlayer { + private $advancedMediaPlayer; + + public function __construct($audioType) { + if ($audioType === "mp4") { + $this->advancedMediaPlayer = new Mp4Player(); + } else if ($audioType === "avi") { + $this->advancedMediaPlayer = new AviPlayer(); + } + } + + public function play($fileName) { + $fileExtension = pathinfo($fileName, PATHINFO_EXTENSION); + if ($fileExtension === "mp4") { + $this->advancedMediaPlayer->playMp4($fileName); + } else if ($fileExtension === "avi") { + $this->advancedMediaPlayer->playAvi($fileName); + } + } +} + +class AudioPlayer implements MediaPlayer { + public function play($fileName) { + $fileExtension = pathinfo($fileName, PATHINFO_EXTENSION); + if ($fileExtension === "mp3") { + echo "Playing MP3 file: " . $fileName . "<br>"; + } else if ($fileExtension === "mp4" || $fileExtension === "avi") { + $mediaAdapter = new MediaAdapter($fileExtension); + $mediaAdapter->play($fileName); + } else { + echo "Invalid media format: " . $fileName . "<br>"; + } + } +} +``` +- Composite : permet de traiter un groupe d'objets de la même manière qu'un objet individuel. +```php +interface Employee { + public function getName(); + public function getSalary(); +} + +class Developer implements Employee { + private $name; + private $salary; + + public function __construct($name, $salary) { + $this->name = $name; + $this->salary = $salary; + } + + public function getName() { + return $this->name; + } + + public function getSalary() { + return $this->salary; + } +} + +class Manager implements Employee { + private $name; + private $salary; + private $subordinates; + + public function __construct($name, $salary) { + $this->name = $name; + $this->salary = $salary; + $this->subordinates = []; + } + + public function getName() { + return $this->name; + } + + public function getSalary() { + return $this->salary; + } + + public function addSubordinate(Employee $employee) { + $this->subordinates[] = $employee; + } + + public function removeSubordinate(Employee $employee) { + $index = array_search($employee, $this->subordinates); + if ($index !== false) { + unset($this->subordinates[$index]); + } + } + + public function getSubordinates() { + return $this->subordinates; + } +} +``` +- Proxy : fournit un substitut ou une représentation de substitution pour un objet afin de contrôler son accès. +- Decorator : permet d'ajouter des fonctionnalités supplémentaires à un objet de manière dynamique. +```php +interface Shape { + public function draw(); +} + +class Rectangle implements Shape { + public function draw() { + echo "Drawing a rectangle.<br>"; + } +} + +class Circle implements Shape { + public function draw() { + echo "Drawing a circle.<br>"; + } +} + +abstract class ShapeDecorator implements Shape { + protected $decoratedShape; + + public function __construct(Shape $decoratedShape) { + $this->decoratedShape = $decoratedShape; + } + + public function draw() { + $this->decoratedShape->draw(); + } +} + +class RedShapeDecorator extends ShapeDecorator { + public function draw() { + parent::draw(); + $this->setRedBorder(); + } + + private function setRedBorder() { + echo "Setting red border.<br>"; + } +} +``` +- Bridge : sépare une abstraction de son implémentation, permettant à chacune d'évoluer indépendamment. +```php +interface Color { + public function applyColor(); +} + +class Red implements Color { + public function applyColor() { + echo "Applying red color.<br>"; + } +} + +class Blue implements Color { + public function applyColor() { + echo "Applying blue color.<br>"; + } +} + +abstract class Shape { + protected $color; + + public function __construct(Color $color) { + $this->color = $color; + } + + public abstract function draw(); +} + +class Circle extends Shape { + public function draw() { + echo "Drawing a circle. "; + $this->color->applyColor(); + } +} + +class Rectangle extends Shape { + public function draw() { + echo "Drawing a rectangle. "; + $this->color->applyColor(); + } +} +``` + +### Patterns comportementaux + +Les patterns comportementaux permettent de modéliser les comportements des objets et d'organiser les interactions entre eux de manière efficace. Ils visent à encapsuler les comportements spécifiques dans des objets distincts et à promouvoir une meilleure séparation des responsabilités. + +Voici quelques exemples de patterns comportementaux couramment utilisés : + +- Observer : Ce pattern définit une dépendance un-à -plusieurs entre objets, de sorte que lorsqu'un objet change d'état, tous ses dépendants en sont notifiés et mis à jour automatiquement. +```php +interface Observer { + public function update($data); +} + +interface Subject { + public function attach(Observer $observer); + public function detach(Observer $observer); + public function notify($data); +} + +class ConcreteSubject implements Subject { + private $observers = []; + + public function attach(Observer $observer) { + $this->observers[] = $observer; + } + + public function detach(Observer $observer) { + $index = array_search($observer, $this->observers); + if ($index !== false) { + unset($this->observers[$index]); + } + } + + public function notify($data) { + foreach ($this->observers as $observer) { + $observer->update($data); + } + } -self + public function doSomething() { + // Faire quelque chose... + + // Notifier les observateurs + $this->notify("Données mises à jour"); + } +} + +class ConcreteObserver implements Observer { + public function update($data) { + echo "Observateur notifié avec les données : " . $data . "<br>"; + } +} +``` +- Strategy : Ce pattern permet de définir une famille d'algorithmes interchangeables. Les algorithmes sont encapsulés dans des classes distinctes, ce qui permet de les sélectionner et de les utiliser dynamiquement selon les besoins. +```php +interface PaymentStrategy { + public function pay($amount); +} + +class CreditCardStrategy implements PaymentStrategy { + private $cardNumber; + private $expirationDate; + private $cvv; + + public function __construct($cardNumber, $expirationDate, $cvv) { + $this->cardNumber = $cardNumber; + $this->expirationDate = $expirationDate; + $this->cvv = $cvv; + } + + public function pay($amount) { + echo "Paying $" . $amount . " with credit card.<br>"; + // Logique de paiement par carte de crédit + } +} + +class PayPalStrategy implements PaymentStrategy { + private $email; + private $password; + + public function __construct($email, $password) { + $this->email = $email; + $this->password = $password; + } + + public function pay($amount) { + echo "Paying $" . $amount . " with PayPal.<br>"; + // Logique de paiement par PayPal + } +} -static +class ShoppingCart { + private $paymentStrategy; + + public function setPaymentStrategy(PaymentStrategy $paymentStrategy) { + $this->paymentStrategy = $paymentStrategy; + } + + public function checkout($amount) { + $this->paymentStrategy->pay($amount); + } +} +``` +- Template Method : Ce pattern définit le squelette d'un algorithme dans une classe de base, en déléguant l'implémentation de certaines étapes aux sous-classes. Il permet ainsi de personnaliser le comportement de l'algorithme sans en modifier la structure globale. +```php +abstract class Game { + abstract protected function initialize(); + abstract protected function startPlay(); + abstract protected function endPlay(); + + public final function play() { + $this->initialize(); + $this->startPlay(); + $this->endPlay(); + } +} + +class FootballGame extends Game { + protected function initialize() { + echo "Football game initialized.<br>"; + } + + protected function startPlay() { + echo "Football game started.<br>"; + } + + protected function endPlay() { + echo "Football game ended.<br>"; + } +} + +class BasketballGame extends Game { + protected function initialize() { + echo "Basketball game initialized.<br>"; + } + + protected function startPlay() { + echo "Basketball game started.<br>"; + } + + protected function endPlay() { + echo "Basketball game ended.<br>"; + } +} +``` +- Command : Ce pattern encapsule une demande en tant qu'objet, ce qui permet de paramétrer les clients avec différentes demandes, de les mettre en file d'attente, de les enregistrer et de les annuler. +- Iterator : Ce pattern fournit un moyen d'accéder séquentiellement aux éléments d'une collection sans exposer la structure interne de la collection. Il permet d'itérer de manière transparente sur les éléments d'une collection. +- State : Ce pattern permet à un objet de modifier son comportement interne lorsqu'il change d'état. Il encapsule chaque état possible dans une classe distincte et permet au contexte d'alterner entre les états de manière transparente. +Ces patterns comportementaux offrent des solutions génériques pour gérer les interactions et les comportements des objets dans un système. Ils améliorent la flexibilité, la réutilisabilité et la maintenabilité du code en promouvant une meilleure séparation des responsabilités et une modularité accrue. \ No newline at end of file -- GitLab