{"id":1208,"date":"2019-02-25T11:21:47","date_gmt":"2019-02-25T09:21:47","guid":{"rendered":"http:\/\/www.lafabriquedecode.com\/blog\/?p=1208"},"modified":"2019-02-25T11:25:52","modified_gmt":"2019-02-25T09:25:52","slug":"php-le-design-pattern-etat","status":"publish","type":"post","link":"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/","title":{"rendered":"PHP \u2013 Le design pattern Etat"},"content":{"rendered":"<p>Le design pattern <strong>Etat<\/strong> est un design pattern <em>comportemental<\/em>; son utilisation est pr\u00e9conis\u00e9e d\u00e8s lors que le comportement d&rsquo;un objet d\u00e9pend directement de l&rsquo;\u00e9tat dans lequel il se trouve \u00e0 l&rsquo;instant T.<\/p>\n<div id=\"attachment_1210\" style=\"width: 510px\" class=\"wp-caption alignnone\"><a href=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2019\/02\/programmeur_vnr.jpg\"><img aria-describedby=\"caption-attachment-1210\" loading=\"lazy\" src=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2019\/02\/programmeur_vnr.jpg\" alt=\"Programmeur \u00e9nerv\u00e9 par l'absence de pattern Etat\" width=\"500\" height=\"332\" class=\"size-full wp-image-1210\" srcset=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2019\/02\/programmeur_vnr.jpg 500w, http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2019\/02\/programmeur_vnr-300x199.jpg 300w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/><\/a><p id=\"caption-attachment-1210\" class=\"wp-caption-text\">Programmeur se mettant dans un \u00e9tat pas possible \u00e0 la lecture d&rsquo;un code \u00e9crit voil\u00e0 10 ans<\/p><\/div>\n<h1>Architecture du design pattern Etat<\/h1>\n<p>Les participants \u00e0 ce design pattern <strong>Etat<\/strong> sont au nombre de 3:<\/p>\n<ul>\n<li>Une <strong>abstraction<\/strong> (interface ou classe abstraite) qui liste les diff\u00e9rents comportements devant \u00eatre impl\u00e9ment\u00e9s par des \u00e9tats concrets<\/li>\n<li>Des \u00e9tats concrets r\u00e9alisant chacune des m\u00e9thodes list\u00e9es dans l&rsquo;abstraction \u00e9voqu\u00e9e ci-dessus<\/li>\n<li>Un <strong>contexte<\/strong> d\u00e9finissant l&rsquo;interface que le code client va utiliser et ayant en <strong>composition<\/strong> les \u00e9tats concrets auquel il va simplement d\u00e9l\u00e9guer les requ\u00eates lui parvenant<\/li>\n<\/ul>\n<h1>Where&rsquo;s the bill, Bill?<\/h1>\n<p>Prenons un exemple parlant: le commerce en ligne ! Une commande faite en ligne traverse toute une s\u00e9rie d&rsquo;\u00e9tats; elle peut \u00eatre cr\u00e9\u00e9e, valid\u00e9e, pay\u00e9e ou mise en recouvrement, annul\u00e9e, rembours\u00e9e, exp\u00e9di\u00e9e etc. Evidemment certaines transitions d&rsquo;\u00e9tat ne peuvent pas se faire: quand elle est exp\u00e9di\u00e9e, elle ne peut pas \u00eatre annul\u00e9e et inversement.<\/p>\n<p>Notre site de vente en ligne d&rsquo;ouvrages informatique CODEBOOKS re\u00e7oit plusieurs centaines de commandes par jour.<br \/>\nUne commande est cr\u00e9\u00e9e dans l&rsquo;\u00e9tat \u00ab\u00a0En Attente\u00a0\u00bb, ce qui signifie qu&rsquo;elle est en attente d&rsquo;une validation, manuelle ou automatique. Cette validation peut intervenir ou pas, si le moyen de paiement s&rsquo;av\u00e8re frauduleux ou s&rsquo;il ne parvient pas dans les d\u00e9lais pr\u00e9cis\u00e9s dans les conditions g\u00e9n\u00e9rales de vente.<\/p>\n<p>Une fois qu&rsquo;elle est valid\u00e9e, elle est pr\u00e9par\u00e9e puis exp\u00e9di\u00e9e afin d&rsquo;\u00eatre livr\u00e9e. C&rsquo;est notre sc\u00e9nario nominal, le <em>Best Case Scenario<\/em>.<br \/>\nD&rsquo;autres scenarii peuvent se produire: l&rsquo;acheteur r\u00e9alise \u00e0 la livraison qu&rsquo;il a d\u00e9j\u00e0 le livre ou bien qu&rsquo;il l&rsquo;a command\u00e9 dans une langue qu&rsquo;il ne sait pas lire; il devra \u00eatre rembours\u00e9 apr\u00e8s renvoi du livre \u00e0 CODEBOOKS. Une erreur de stock peut \u00e9galement conduire \u00e0 valider une commande portant sur un livre non disponible, elle devra donc \u00eatre annul\u00e9e puis rembours\u00e9e.<\/p>\n<h1>Tes \u00e9tats d&rsquo;\u00e2me, Eric&#8230;(air bien connu)<\/h1>\n<h2>Nos \u00e9tats<\/h2>\n<p>Chacun de nos \u00e9tats fera l&rsquo;objet d&rsquo;une classe concr\u00e8te d\u00e9rivant une classe abstraite (ou impl\u00e9mentant une interface, au choix). J&rsquo;ai choisi une classe abstraite dans laquelle je factorise mon constructeur, pour \u00e9viter de le r\u00e9p\u00e9ter b\u00eatement dans chaque classe fille car il fait dans tous les cas la m\u00eame chose. Cette classe abstraite impl\u00e9mente une interface qui va contraindre chacune des classes filles \u00e0 impl\u00e9menter l&rsquo;ensemble des m\u00e9thodes qu&rsquo;un \u00e9tat pourra mettre \u00e0 disposition. Notez bien que le contexte est en composition de chacun des \u00e9tats concrets, pour garder la trace de l&rsquo;\u00e9tat courant d&rsquo;une commande.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\ninterface EtatInterface\r\n{\r\n    public function mettreEnAttente(): void;\r\n    public function valider(): void;\r\n    public function annuler(): void;\r\n    public function rembourser(): void;\r\n    public function expedier(): void;\r\n    public function signalerLivre(): void;\r\n}\r\n\r\nabstract class EtatAbstract implements EtatInterface\r\n{\r\n    protected $contexte;\r\n    \r\n    public function __construct(ContexteInterface $contexte)\r\n    {\r\n        $this-&gt;contexte = $contexte;\r\n    }\r\n}\r\n<\/pre>\n<p>Apr\u00e8s \u00e9tude, nous avons d\u00e9termin\u00e9 les \u00e9tats possibles d&rsquo;une commande:<\/p>\n<ul>\n<li>En Attente: c&rsquo;est l&rsquo;\u00e9tat par d\u00e9faut, celui dans lequel se trouve toute commande \u00ab\u00a0atterrissant\u00a0\u00bb sur notre syst\u00e8me d&rsquo;information<\/li>\n<li>Annul\u00e9<\/li>\n<li>Valid\u00e9<\/li>\n<li>Exp\u00e9di\u00e9<\/li>\n<li>Rembours\u00e9<\/li>\n<li>Livr\u00e9<\/li>\n<\/ul>\n<p>Vous allez me dire \u00ab\u00a0Mais avec cette interface, l&rsquo;\u00e9tat <em>Annul\u00e9<\/em> va se retrouver \u00e0 devoir impl\u00e9menter une m\u00e9thode <strong>expedier<\/strong> alors qu&rsquo;il ne doit pas pouvoir transiter vers cet \u00e9tat !\u00a0\u00bb et vous aurez tout \u00e0 fait raison ! C&rsquo;est comme \u00e7a, il nous faut une interface qui liste toutes les m\u00e9thodes qu&rsquo;on peut invoquer sur l&rsquo;ensemble des \u00e9tats pour faire plaisir \u00e0 ce bon vieux <strong>Liskov<\/strong> !<\/p>\n<p>D\u00e8s qu&rsquo;une m\u00e9thode sera appel\u00e9e sur un \u00e9tat qui ne doit pas l&rsquo;impl\u00e9menter, nous l\u00e8verons une exception maison nomm\u00e9e <strong>MethodNotImplementedException<\/strong>:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass MethodNotImplementedException extends \\Exception {}\r\n<\/pre>\n<h2>Le contexte<\/h2>\n<p>Notre contexte va \u00eatre appel\u00e9 par le code client, c&rsquo;est lui qui va garder une trace de l&rsquo;\u00e9tat courant de notre commande. Il a en composition une instance de chacun des diff\u00e9rents types d&rsquo;\u00e9tats disponibles dans lesquels il va s&rsquo;auto-injecter et \u00e0 sa construction, il mettra l&rsquo;\u00e9tat courant \u00e0 sa valeur par d\u00e9faut, \u00e0 savoir \u00ab\u00a0en attente\u00a0\u00bb. Il propose une s\u00e9rie de <em>getters<\/em> (sauf pour <em>enAttente<\/em> car nous postulons qu&rsquo;aucun \u00e9tat ne peut effectuer de transition vers cet \u00e9tat initial) ainsi que les m\u00e9thodes que le code client appellera. Vous notez que ces m\u00e9thodes font de la d\u00e9l\u00e9gation b\u00eate et m\u00e9chante. L&rsquo;unique <em>setter<\/em> est crucial pour tenir le contexte \u00e0 jour des changements d&rsquo;\u00e9tat intervenus dans l&rsquo;application.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\ninterface ContexteInterface\r\n{\r\n    public function etatValide(): EtatInterface;\r\n    public function etatAnnule(): EtatInterface;\r\n    public function etatExpedie(): EtatInterface;\r\n    public function etatLivre(): EtatInterface;\r\n    public function etatActuel(): EtatInterface;\r\n    public function changerEtat(EtatInterface $etat): void;\r\n}\r\n\r\nclass Contexte implements ContexteInterface\r\n{\r\n    private $enAttente;\r\n    private $valide;\r\n    private $expedie;\r\n    private $livre;\r\n    private $rembourse;\r\n    private $annule;\r\n    private $etatActuel;\r\n\r\n    public function __construct()\r\n    {\r\n        $this-&gt;enAttente = new EnAttente($this);\r\n        $this-&gt;valide = new Valide($this);\r\n        $this-&gt;expedie = new Expedie($this);\r\n        $this-&gt;livre = new Livre($this);\r\n        $this-&gt;rembourse = new Rembourse($this);\r\n        $this-&gt;annule = new Annule($this);\r\n        \r\n        $this-&gt;etatActuel = $this-&gt;enAttente;\r\n    }\r\n    \r\n    public function etatValide(): EtatInterface\r\n    {\r\n        return $this-&gt;valide;\r\n    }\r\n    \r\n    public function etatAnnule(): EtatInterface\r\n    {\r\n        return $this-&gt;annule;\r\n    }\r\n    \r\n    public function etatExpedie(): EtatInterface\r\n    {\r\n        return $this-&gt;expedie;\r\n    }\r\n    \r\n    public function etatLivre(): EtatInterface\r\n    {\r\n        return $this-&gt;livre;\r\n    }\r\n    \r\n    public function etatRembourse(): EtatInterface\r\n    {\r\n        return $this-&gt;rembourse;\r\n    }\r\n    \r\n    public function etatActuel(): EtatInterface\r\n    {\r\n        return $this-&gt;etatActuel;\r\n    }\r\n    \r\n    public function changerEtat(EtatInterface $etat): void\r\n    {\r\n        $this-&gt;etatActuel = $etat;\r\n    }\r\n    \r\n    public function valider(): void\r\n    {\r\n        $this-&gt;etatActuel-&gt;valider();\r\n    }\r\n    \r\n    public function expedier(): void\r\n    {\r\n        $this-&gt;etatActuel-&gt;expedier();\r\n    }\r\n    \r\n    public function signalerCommeLivre(): void\r\n    {\r\n        $this-&gt;etatActuel-&gt;signalerLivre();\r\n    }\r\n    \r\n    public function effectuerRemboursement(): void\r\n    {\r\n        $this-&gt;etatActuel-&gt;rembourser();\r\n    }\r\n    \r\n    public function effectuerAnnulation(): void\r\n    {\r\n        $this-&gt;etatActuel-&gt;annuler();\r\n    }\r\n}\r\n<\/pre>\n<h2>Nos \u00e9tats&#8230;concrets !<\/h2>\n<h3>EnAttente<\/h3>\n<p>Prenons notre premi\u00e8re classe concr\u00e8te: <em>EnAttente<\/em>. Cet \u00e9tat peut effectuer des transitions vers les \u00e9tats <em>Valid\u00e9<\/em> (si le paiement est valide) ou <em>Annul\u00e9<\/em> (dans le cas contraire). Il ne peut pas le faire vers lui-m\u00eame ainsi que vers les \u00e9tats <em>Rembours\u00e9<\/em>, <em>Exp\u00e9di\u00e9<\/em> et <em>Livr\u00e9<\/em> car \u00e0 ce stade le paiement de la commande n&rsquo;est pas une certitude.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass EnAttente extends EtatAbstract\r\n{   \r\n    public function mettreEnAttente(): void\r\n    {\r\n        throw new MethodNotImplementedException('D\u00e9j\u00e0 en attente');\r\n    }\r\n    \r\n    public function valider(): void\r\n    {\r\n        $this-&gt;contexte-&gt;changerEtat($this-&gt;contexte-&gt;etatValide());\r\n    }\r\n    \r\n    public function annuler(): void\r\n    {\r\n        $this-&gt;contexte-&gt;changerEtat($this-&gt;contexte-&gt;etatAnnule());\r\n    }\r\n    \r\n    public function rembourser(): void\r\n    {\r\n        throw new MethodNotImplementedException('En attente');\r\n    }\r\n    \r\n    public function expedier(): void\r\n    {\r\n        throw new MethodNotImplementedException('En attente');\r\n    }\r\n    \r\n    public function signalerLivre(): void\r\n    {\r\n        throw new MethodNotImplementedException('En attente');\r\n    }\r\n}\r\n<\/pre>\n<h3>Annul\u00e9<\/h3>\n<p>Comme tous les \u00e9tats, <em>Annule<\/em> ne peut aller vers lui-m\u00eame et il n&rsquo;effectue de transition qu&rsquo;en direction de <em>Rembours\u00e9<\/em>.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass Annule extends EtatAbstract\r\n{\r\n    public function mettreEnAttente(): void\r\n    {\r\n        throw new MethodNotImplementedException('Annul\u00e9');\r\n    }\r\n    \r\n    public function valider(): void\r\n    {\r\n        throw new MethodNotImplementedException('Annul\u00e9');\r\n    }\r\n    \r\n    public function annuler(): void\r\n    {\r\n        throw new MethodNotImplementedException('D\u00e9j\u00e0 annul\u00e9');\r\n    }\r\n    \r\n    public function rembourser(): void\r\n    {\r\n        $this-&gt;contexte-&gt;changerEtat($this-&gt;contexte-&gt;etatRembourse());\r\n    }\r\n    \r\n    public function expedier(): void\r\n    {\r\n        throw new MethodNotImplementedException('Annul\u00e9');\r\n    }\r\n    \r\n    public function signalerLivre(): void\r\n    {\r\n        throw new MethodNotImplementedException('Annul\u00e9');\r\n    }\r\n}\r\n<\/pre>\n<h3>Valid\u00e9<\/h3>\n<p><em>Valide<\/em> peut \u00e9voluer en <em>Annul\u00e9<\/em> (opposition bancaire ou autres) ou en <em>Exp\u00e9di\u00e9<\/em>, si tout se d\u00e9roule normalement.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass Valide extends EtatAbstract\r\n{    \r\n    public function mettreEnAttente(): void\r\n    {\r\n        throw new MethodNotImplementedException('Valid\u00e9');\r\n    }\r\n    \r\n    public function valider(): void\r\n    {\r\n        throw new MethodNotImplementedException('D\u00e9j\u00e0 valid\u00e9');\r\n    }\r\n    \r\n    public function annuler(): void\r\n    {\r\n        $this-&gt;contexte-&gt;changerEtat($this-&gt;contexte-&gt;etatAnnule());\r\n    }\r\n    \r\n    public function rembourser(): void\r\n    {\r\n        throw new MethodNotImplementedException('Valid\u00e9');\r\n    }\r\n    \r\n    public function expedier(): void\r\n    {\r\n        $this-&gt;contexte-&gt;changerEtat($this-&gt;contexte-&gt;etatExpedie());\r\n    }\r\n    \r\n    public function signalerLivre(): void\r\n    {\r\n        throw new MethodNotImplementedException('Valid\u00e9');\r\n    }\r\n}\r\n<\/pre>\n<h3>Expedi\u00e9<\/h3>\n<p>Cet \u00e9tat peut effectuer des transitions uniquement vers <em>Livr\u00e9<\/em>.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass Expedie extends EtatAbstract\r\n{   \r\n    public function mettreEnAttente(): void\r\n    {\r\n        throw new MethodNotImplementedException('Exp\u00e9di\u00e9');\r\n    }\r\n    \r\n    public function valider(): void\r\n    {\r\n        throw new MethodNotImplementedException('Exp\u00e9di\u00e9');\r\n    }\r\n    \r\n    public function annuler(): void\r\n    {\r\n        throw new MethodNotImplementedException('Exp\u00e9di\u00e9');\r\n    }\r\n    \r\n    public function rembourser(): void\r\n    {\r\n        throw new MethodNotImplementedException('Exp\u00e9di\u00e9');\r\n    }\r\n    \r\n    public function expedier(): void\r\n    {\r\n        throw new MethodNotImplementedException('D\u00e9j\u00e0 exp\u00e9di\u00e9');\r\n    }\r\n    \r\n    public function signalerLivre(): void\r\n    {\r\n        $this-&gt;contexte-&gt;changerEtat($this-&gt;contexte-&gt;etatLivre());\r\n    }\r\n}\r\n<\/pre>\n<h3>Rembours\u00e9<\/h3>\n<p>C&rsquo;est un \u00e9tat <strong>terminal<\/strong>.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass Rembourse extends EtatAbstract\r\n{\r\n    public function mettreEnAttente(): void\r\n    {\r\n        throw new MethodNotImplementedException('Rembours\u00e9');\r\n    }\r\n    \r\n    public function valider(): void\r\n    {\r\n        throw new MethodNotImplementedException('Rembours\u00e9');\r\n    }\r\n    \r\n    public function annuler(): void\r\n    {\r\n        throw new MethodNotImplementedException('Rembours\u00e9');\r\n    }\r\n    \r\n    public function rembourser(): void\r\n    {\r\n        throw new MethodNotImplementedException('D\u00e9j\u00e0 Rembours\u00e9');\r\n    }\r\n    \r\n    public function expedier(): void\r\n    {\r\n        throw new MethodNotImplementedException('Rembours\u00e9');\r\n    }\r\n    \r\n    public function signalerLivre(): void\r\n    {\r\n        throw new MethodNotImplementedException('Rembours\u00e9');\r\n    }\r\n}\r\n<\/pre>\n<h3>Livr\u00e9<\/h3>\n<p>Cet \u00e9tat ne peut transiter que vers <em>Annul\u00e9<\/em>, quand le client re\u00e7oit un produit qui ne lui convient pas. L&rsquo;annulation donnera ensuite lieu \u00e0 un remboursement.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass Livre extends EtatAbstract\r\n{\r\n    public function mettreEnAttente(): void\r\n    {\r\n        throw new MethodNotImplementedException('Livr\u00e9');\r\n    }\r\n    \r\n    public function valider(): void\r\n    {\r\n        throw new MethodNotImplementedException('Livr\u00e9');\r\n    }\r\n    \r\n    public function annuler(): void\r\n    {\r\n        $this-&gt;contexte-&gt;changerEtat($this-&gt;contexte-&gt;etatAnnule());\r\n    }\r\n    \r\n    public function rembourser(): void\r\n    {\r\n        throw new MethodNotImplementedException('Livr\u00e9');\r\n    }\r\n    \r\n    public function expedier(): void\r\n    {\r\n        throw new MethodNotImplementedException('Livr\u00e9');\r\n    }\r\n    \r\n    public function signalerLivre(): void\r\n    {\r\n        throw new MethodNotImplementedException('D\u00e9j\u00e0 Livr\u00e9');\r\n    }\r\n}\r\n<\/pre>\n<h2>Le code client<\/h2>\n<p>Nous avons \u00e0 notre disposition une classe <strong>Commande<\/strong>; elle poss\u00e8de une r\u00e9f\u00e9rence vers le contexte, qui va ainsi garder trace des diff\u00e9rents \u00e9tats qu&rsquo;elle traverse. C&rsquo;est elle que notre code client va appeler.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass Commande\r\n{\r\n    private $contexte;\r\n    \r\n    public function __construct(ContexteInterface $contexte)\r\n    {\r\n        $this-&gt;contexte = $contexte;\r\n    }\r\n    \r\n    public function valider(): void\r\n    {\r\n        $this-&gt;contexte-&gt;valider();\r\n        echo &quot;Etat = &quot;.get_class($this-&gt;contexte-&gt;etatActuel()).PHP_EOL;\r\n    }\r\n\r\n    public function expedier(): void\r\n    {\r\n        $this-&gt;contexte-&gt;expedier();\r\n        echo &quot;Etat = &quot;.get_class($this-&gt;contexte-&gt;etatActuel()).PHP_EOL;\r\n    }\r\n    \r\n    public function signalerCommeEtantLivre(): void\r\n    {\r\n        $this-&gt;contexte-&gt;signalerCommeLivre();\r\n        echo &quot;Etat = &quot;.get_class($this-&gt;contexte-&gt;etatActuel()).PHP_EOL;\r\n    }\r\n    \r\n    public function procederAuRemboursement(): void\r\n    {\r\n        $this-&gt;contexte-&gt;effectuerRemboursement();\r\n        echo &quot;Etat = &quot;.get_class($this-&gt;contexte-&gt;etatActuel()).PHP_EOL;\r\n    }\r\n \r\n    public function effectuerUneAnnulation(): void\r\n    {\r\n        $this-&gt;contexte-&gt;effectuerAnnulation();\r\n        echo &quot;Etat = &quot;.get_class($this-&gt;contexte-&gt;etatActuel()).PHP_EOL;\r\n    }\r\n    \r\n}\r\n\r\n$contexte = new Contexte();\r\n$commande = new Commande($contexte);\r\n<\/pre>\n<p>Voici notre sc\u00e9nario nominal, ou <em>best case scenario<\/em> (fingaz crossed!) :<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n$commande-&gt;valider();\r\n$commande-&gt;expedier();\r\n$commande-&gt;signalerCommeEtantLivre();\r\n<\/pre>\n<p>La commande va traverser 4 \u00e9tats: elle va passer de \u00ab\u00a0en attente\u00a0\u00bb \u00e0 \u00ab\u00a0valid\u00e9e\u00a0\u00bb, puis \u00e0 \u00ab\u00a0exp\u00e9di\u00e9e\u00a0\u00bb et enfin \u00e0 \u00ab\u00a0livr\u00e9e\u00a0\u00bb.<\/p>\n<p>Voici le sc\u00e9nario o\u00f9 la commande est valid\u00e9e mais une erreur de stock conduit \u00e0 devoir l&rsquo;annuler et la rembourser:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n$commande-&gt;valider();\r\n$commande-&gt;effectuerUneAnnulation();\r\n$commande-&gt;procederAuRemboursement(); \/\/ \u00e9tat TERMINAL\r\n<\/pre>\n<p>Dans le sc\u00e9nario suivant, le produit est livr\u00e9 mais l&rsquo;acheteur r\u00e9alise qu&rsquo;il l&rsquo;a d\u00e9j\u00e0 ou bien qu&rsquo;il s&rsquo;est tromp\u00e9 lors de sa commande et le produit de remplacement n&rsquo;est plus disponible dans le stock:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n$commande-&gt;valider();\r\n$commande-&gt;expedier();\r\n$commande-&gt;signalerCommeEtantLivre();\r\n$commande-&gt;effectuerUneAnnulation();\r\n$commande-&gt;procederAuRemboursement(); \/\/ \u00e9tat TERMINAL\r\n<\/pre>\n<p>Enfin, dans notre dernier sc\u00e9nario, le paiement n&rsquo;est pas arriv\u00e9 \u00e0 temps (mandat, virement bancaire, ch\u00e8que&#8230;) et il faut annuler la commande ! C&rsquo;est le plus simple:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n$commande-&gt;effectuerUneAnnulation();\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Le design pattern Etat est un design pattern comportemental; son utilisation est pr\u00e9conis\u00e9e d\u00e8s lors que le comportement d&rsquo;un objet d\u00e9pend directement de l&rsquo;\u00e9tat dans lequel il se trouve \u00e0 l&rsquo;instant T. Architecture du design pattern Etat Les participants \u00e0 ce design pattern Etat sont au nombre de 3: Une abstraction (interface ou classe abstraite) [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[40,14,88],"tags":[43,101,4],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.6.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>PHP \u2013 Le design pattern Etat - La Fabrique de code - Tech blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"PHP \u2013 Le design pattern Etat - La Fabrique de code - Tech blog\" \/>\n<meta property=\"og:description\" content=\"Le design pattern Etat est un design pattern comportemental; son utilisation est pr\u00e9conis\u00e9e d\u00e8s lors que le comportement d&rsquo;un objet d\u00e9pend directement de l&rsquo;\u00e9tat dans lequel il se trouve \u00e0 l&rsquo;instant T. Architecture du design pattern Etat Les participants \u00e0 ce design pattern Etat sont au nombre de 3: Une abstraction (interface ou classe abstraite) [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/\" \/>\n<meta property=\"og:site_name\" content=\"La Fabrique de code - Tech blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-02-25T09:21:47+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-02-25T09:25:52+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2019\/02\/programmeur_vnr.jpg\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary\" \/>\n<meta name=\"twitter:creator\" content=\"@LaFabrique2Code\" \/>\n<meta name=\"twitter:site\" content=\"@LaFabrique2Code\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/\",\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/\",\"name\":\"PHP \u2013 Le design pattern Etat - La Fabrique de code - Tech blog\",\"isPartOf\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#website\"},\"datePublished\":\"2019-02-25T09:21:47+00:00\",\"dateModified\":\"2019-02-25T09:25:52+00:00\",\"author\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162\"},\"breadcrumb\":{\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"http:\/\/www.lafabriquedecode.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"PHP \u2013 Le design pattern Etat\"}]},{\"@type\":\"WebSite\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#website\",\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/\",\"name\":\"La Fabrique de code - Tech blog\",\"description\":\"PHP objet, MySQL, Design Patterns, OOP...et plus !\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"http:\/\/www.lafabriquedecode.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Person\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g\",\"contentUrl\":\"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g\",\"caption\":\"admin\"},\"url\":\"http:\/\/www.lafabriquedecode.com\/blog\/author\/admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"PHP \u2013 Le design pattern Etat - La Fabrique de code - Tech blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/","og_locale":"fr_FR","og_type":"article","og_title":"PHP \u2013 Le design pattern Etat - La Fabrique de code - Tech blog","og_description":"Le design pattern Etat est un design pattern comportemental; son utilisation est pr\u00e9conis\u00e9e d\u00e8s lors que le comportement d&rsquo;un objet d\u00e9pend directement de l&rsquo;\u00e9tat dans lequel il se trouve \u00e0 l&rsquo;instant T. Architecture du design pattern Etat Les participants \u00e0 ce design pattern Etat sont au nombre de 3: Une abstraction (interface ou classe abstraite) [&hellip;]","og_url":"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/","og_site_name":"La Fabrique de code - Tech blog","article_published_time":"2019-02-25T09:21:47+00:00","article_modified_time":"2019-02-25T09:25:52+00:00","og_image":[{"url":"http:\/\/www.lafabriquedecode.com\/blog\/wp-content\/uploads\/2019\/02\/programmeur_vnr.jpg"}],"author":"admin","twitter_card":"summary","twitter_creator":"@LaFabrique2Code","twitter_site":"@LaFabrique2Code","twitter_misc":{"\u00c9crit par":"admin","Dur\u00e9e de lecture estim\u00e9e":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/","url":"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/","name":"PHP \u2013 Le design pattern Etat - La Fabrique de code - Tech blog","isPartOf":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/#website"},"datePublished":"2019-02-25T09:21:47+00:00","dateModified":"2019-02-25T09:25:52+00:00","author":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162"},"breadcrumb":{"@id":"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/#breadcrumb"},"inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/"]}]},{"@type":"BreadcrumbList","@id":"http:\/\/www.lafabriquedecode.com\/blog\/2019\/02\/php-le-design-pattern-etat\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"http:\/\/www.lafabriquedecode.com\/blog\/"},{"@type":"ListItem","position":2,"name":"PHP \u2013 Le design pattern Etat"}]},{"@type":"WebSite","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#website","url":"http:\/\/www.lafabriquedecode.com\/blog\/","name":"La Fabrique de code - Tech blog","description":"PHP objet, MySQL, Design Patterns, OOP...et plus !","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"http:\/\/www.lafabriquedecode.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"fr-FR"},{"@type":"Person","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/83863c048b82fd9ccf6407bddd241162","name":"admin","image":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"http:\/\/www.lafabriquedecode.com\/blog\/#\/schema\/person\/image\/","url":"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g","contentUrl":"http:\/\/0.gravatar.com\/avatar\/fc2e1de7c8a1871b50ff9c6a6f8682a2?s=96&d=retro&r=g","caption":"admin"},"url":"http:\/\/www.lafabriquedecode.com\/blog\/author\/admin\/"}]}},"_links":{"self":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/1208"}],"collection":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/comments?post=1208"}],"version-history":[{"count":18,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/1208\/revisions"}],"predecessor-version":[{"id":1227,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/posts\/1208\/revisions\/1227"}],"wp:attachment":[{"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/media?parent=1208"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/categories?post=1208"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.lafabriquedecode.com\/blog\/wp-json\/wp\/v2\/tags?post=1208"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}