Compare commits

...

2 Commits

Author SHA1 Message Date
Fred Pauchet 9a696c8211 Describe Composite pattern 2024-03-26 15:08:29 +01:00
Fred Pauchet 0d9d90cd3d Describe the Template pattern 2024-03-26 14:55:29 +01:00
6 changed files with 161 additions and 1 deletions

View File

@ -0,0 +1,58 @@
<mxfile host="Electron" modified="2024-03-26T08:10:45.260Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.0.3 Chrome/114.0.5735.289 Electron/25.8.4 Safari/537.36" etag="ChN9pPi8goOMF3hpUA-N" version="22.0.3" type="device">
<diagram name="Page-1" id="hcI3l78rCcP6oUjfjhzO">
<mxGraphModel dx="954" dy="598" grid="0" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="8Q815A0daQfj0QbWb1XH-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="8Q815A0daQfj0QbWb1XH-1" target="8Q815A0daQfj0QbWb1XH-9" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-1" value="Character" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="120" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="8Q815A0daQfj0QbWb1XH-2" target="8Q815A0daQfj0QbWb1XH-1" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-2" value="Queen" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="30" y="230" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="8Q815A0daQfj0QbWb1XH-3" target="8Q815A0daQfj0QbWb1XH-1" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-3" value="King" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="230" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="8Q815A0daQfj0QbWb1XH-4" target="8Q815A0daQfj0QbWb1XH-1" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-4" value="..." style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="370" y="230" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-8" value="is-a" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="250" y="180" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-9" value="Weapon Behaviour" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="550" y="120" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-11" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="8Q815A0daQfj0QbWb1XH-10" target="8Q815A0daQfj0QbWb1XH-9" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-10" value="Knife Behaviour" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="550" y="230" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-13" value="as-a" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="420" y="120" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="8Q815A0daQfj0QbWb1XH-14" target="8Q815A0daQfj0QbWb1XH-9" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-14" value="..." style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="730" y="230" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="8Q815A0daQfj0QbWb1XH-16" value="is-a" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="600" y="180" width="60" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -26,21 +26,110 @@ Pour rappel, la Programmation Orientée Objets se base sur les principes suivant
### Factory & Abstract Factory
### Singleton
## Behavioral
### Command
### Iterator
### Template
Celui-ci, c'est un peu mon chouchou.
Il consiste à définir les grandes étapes du comportement d'un modèle, pouvant être réutilisé entre plusieurs autres définitions.
Ainsi, les deux classes ci-dessous présentent les mêmes étapes d'un algorithme - elles sont juste nommées différemment :
```python
class Coffee:
def boil_water(self):
...
def brew_coffee_grinds(self):
...
def pour_in_cup(self):
...
def add_sugar_and_milk(self):
...
class Tea:
def boil_water(self):
...
def steep_tea_bag(self):
...
def pour_in_cup(self):
...
def add_lemon(self):
...
```
On peut voir que la finalité est la même ("_servir une boisson chaude_"), tandis que les étapes varient légèrement, mais restent fortement similaires, et consistent à :
1. Faire bouillir de l'eau,
2. Préparer l'infusion,
3. Servir dans une tasse,
4. Ajouter des condiments.
Ces quatre étapes constituent les quatre méthodes principales d'une classe `CaffeineBeverage`, que l'on peut traduire de la manière suivante :
```python
class CaffeineBeverage:
def boil_water(self):
...
def brew(self):
raise NotImplementedError()
def pour_in_cup(self):
...
def add_condiments(self):
...
```
Nous pouvons à présent modéliser nos deux (sous-)classes `Coffee` & `Tea` simplement en surchargeant les méthodes qui nous intéressent, et en laissant le template faire le reste de son travail :
```python
class Coffee(CaffeineBeverage):
[snip]
def brew(self):
self.brew_coffee_grinds()
class Tea(CaffeineBeverage)
[snip]
def brew(self):
self.steep_tea_bag()
```
![](template.png)
Le _template_ définit donc le squelette d'un algorithme dans une méthode, en autorisant aux sous-classes de surcharger certaines parties de cet algorithme, sans en changer la nature intrinsèque.
Il est tout aussi facile de définir des _hooks_, qui permettent à la sous-classe de définir un comportement sur base de _flags_.
Les tableaux utilisent ce pattern pour les tris en utilisant les méthodes `.CompareTo()` (ou équivalentes) ou la surcharge d'opérateurs (`__lte__`, `__gte__`, ...).
### State
### Observer
### Strategy
> Plutôt que d'implémenter une forme d'héritage dès qu'on en a l'occasion, l'idée est de différencier l'élément de son comportement.
@ -55,7 +144,7 @@ De cette manière, il suffit de déclarer une nouvelle classe, puis de lui injec
Une autre conclusion est qu'il est parfois mieux d'implémenter un `has-a` (= composition, délégation, ...) qu'un `is-a` (= héritage).
De la même manière, nous pouvons implémenter des personnes d'un jeu de rôles et "réutiliser" leurs armes en définissant un `WeaponBehaviour` :
![](strategy.drawio.png)
![](strategy.png)
[^1]: en mode, "_Si vous faites de l'héritage sans réfléchir, vous allez vous planter_".
@ -63,12 +152,25 @@ De la même manière, nous pouvons implémenter des personnes d'un jeu de rôles
### Composite
L'intérêt des composite est de représenter des éléments contenant d'autres éléments d'un même type.
Le modèle analysé se base sur des "menus" (d'un restaurant), qui peuvent contenir d'autres sous-menus.
Il s'agit donc d'un _pattern_ pouvant servir à représenter des arborescences - où nous trouverons des noeuds et des feuilles d'un arbre.
![](composite.png)
Attention qu'en termes de performances, ce pattern doit généralement être couplé à d'autres mécanismes (caching, dénormalisation, [MPTT](https://stackabuse.com/modified-preorder-tree-traversal-in-django/), ...).
### Decorator
### Adapter
### Façade
### Proxy
### Compound

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB