您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
此存儲庫已封存,您能瀏覽檔案及複製此存儲庫,但不能推送、建立問題及拉取請求。

03-composition.md 2.9 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. +++
  2. title = "Composition"
  3. weight = 3
  4. +++
  5. # Composition
  6. ## Définition
  7. Une classe à l'intérieur d'une autre classe.
  8. ## Dépendances entre fonctions
  9. Exemple: on veut dessiner un sapin dans le terminal:
  10. ```python
  11. def main():
  12. largeur = demander_largeur()
  13. dessine_sapin(largeur)
  14. main()
  15. ```
  16. On voit que la fonction `dessine_sapin()` prend un argument `largeur`, qui est retourné
  17. par la fonction `demander_largeur()`.
  18. `dessine_sapin()` doit donc être appelée *après* `demander_largeur()`. On dit que `dessine_sapin()`
  19. _dépend_ de `demander_largeur()`.
  20. ## Dépendances entre classes
  21. Un bon moyen d'introduire une dépendance entre deux classes est d'utiliser les constructeurs.
  22. Revoyons la classe Chat:
  23. ```python
  24. class Chat:
  25. def __init__(self, nom):
  26. self.nom = nome
  27. ```
  28. Comme le constructeur de la classe Chat prend un nom en argument, il est impossible de construire
  29. des chats sans nom:
  30. ```python
  31. >>> chat = Chat()
  32. TypeError: __init__() missing 1 required positional argument: 'nom'
  33. ```
  34. De la même façon, si on veut que tous les enfants aient un chat (pourquoi pas, après tout), on peut
  35. avoir une classe Enfant, dont le constructeur prend une instance de chat en plus du prénom:
  36. ```python
  37. class Enfant:
  38. def __init__(self, prénom, chat):
  39. self.prénom = prénom
  40. self.chat = chat
  41. >>> alice = Enfant("Alice")
  42. TypeError: __init__() missing 1 required positional argument: 'chat'
  43. >>> boule_de_poils = Chat("Boule de Poils")
  44. >>> alice = Enfant("Alice", boule_de_poils)
  45. # OK!
  46. ```
  47. ## Utilisation de la composition
  48. Maintenant qu'on vit dans un monde où tous les enfants ont chacun un chat, on peut
  49. par exemple consoler tous les enfants en leur demandant de caresser leur chat, chat
  50. qui va ronronner et faire plaisir à son propriétaire.
  51. Voici comment on peut coder cela: d'abord, on rajoute les méthodes `caresse()`
  52. et `ronronne()` dans la classe Chat:
  53. ```python
  54. class Chat:
  55. def __init__(self, nom):
  56. self.nom = nom
  57. def ronronne(self):
  58. print(self.nom, 'fait: "prrrrr"')
  59. def caresse(self):
  60. self.ronronne()
  61. >>> boule_de_poils = Chat("Boule de Poils")
  62. >>> boule_de_poils.caresse()
  63. Boule de Poils fait "prrrrr"
  64. ```
  65. Ensuite, on peut rajouter la méthode `console()` dans la classe Enfant,
  66. qui va:
  67. * récupérer l'instance de la classe Chat dans `self` - comme n'importe quel attribut
  68. * puis appeler la méthode `caresse()` de cette instance
  69. ```python
  70. class Enfant:
  71. def __init__(self, prénom, chat):
  72. self.chat = chat
  73. def console(self):
  74. self.chat.caresse()
  75. >>> boule_de_poils = Chat("Boule de Poils")
  76. >>> alice = Enfant("Alice", boule_de_poils)
  77. # Alice est triste, on la console
  78. >>> alice.console()
  79. Boule de Poils fait "prrrrr"
  80. # Alice est consolée :)
  81. ```
  82. On dit parfois qu'on a *délégué* l'implémentation de la méthode `console()` de la classe Enfant
  83. à la méthode `caresse()` de la classe Chat.