Dans le chapitre précédent, nous avons utilisé une énumération pour modifier l'initialisation de la classe RoadSection
, ce qui nous a permis d'écrire ceci :
RoadSection(type: .plain)
RoadSection(type: .home)
RoadSection(type: .school)
C'est déjà bien, mais ce n'est pas exactement l'objectif souhaité. À l'origine, nous souhaitions utiliser l'héritage pour initialiser différents types de sections de route. On aimerait plutôt pouvoir écrire ceci :
RoadSection()
HomeRoadSection()
SchoolRoadSection()
Alors, allons-y !
Ca va être super !
Je vous propose de commencer tout simplement par déclarer nos classes HomeRoadSection
et SchoolRoadSection
en les faisant hériter de RoadSection
:
class HomeRoadSection: RoadSection {
}
class SchoolRoadSection: RoadSection {
}
C'est un bon début. Maintenant nous allons les initialiser en dessinant sur le canevas la section de route correspondante :
class HomeRoadSection: RoadSection {
init() {
}
}
class SchoolRoadSection: RoadSection {
init() {
}
}
Et là, réfléchissons un peu. Nous avons déjà fait le travail dans l'initialisation de RoadSection
pour que la bonne section de canevas soit dessinée en fonction de son type. Est-ce qu'il n'y aurait pas un moyen de réutiliser l'initialisation de RoadSection
dans ses classes filles ?
Vous vous en doutez, il y a moyen. Et le moyen, c'est super
! Oui le mot super
. Le mot super
dans une classe permet de faire référence à la classe mère de la classe dans laquelle on se trouve. C'est un peu l'équivalent du mot self
. Sauf que self
fais référence à soi-même alors que super
fait référence à la classe mère.
Donc ici, nous allons utiliser super
pour récupérer l'initialisation de RoadSection
:
class HomeRoadSection: RoadSection {
init() {
super.init(type: .home)
}
}
class SchoolRoadSection: RoadSection {
init() {
super.init(type: .school)
}
}
Maintenant, voyons ce qu'il se passe si j'écris ceci :
HomeRoadSection()
Je vais tout d'abord appeler l'initialisation de HomeRoadSection
. Ensuite, je vais, par le mot clé super,
appeler l'initialisation de RoadSection
en lui passant le paramètre .home
. Cela nous fait passer dans un switch qui appelle la méthode : canvas.createHomeRoadSection()
.
Maintenant, je vous propose de rajouter la propriété children
à la classe HomeRoadSection
qui va nous permettre de savoir combien d'enfants habitent la maison. J'en profite en même temps pour l'inclure dans notre initialisation.
class HomeRoadSection: RoadSection {
var children: Int
init(children: Int) {
self.children = children
super.init(type: .home)
}
}
À la conduite !
Nos sections de route sont maintenant très pratiques, mais notre bus scolaire a encore triste mine :
class SchoolBus: Bus {
var schoolName = ""
}
Pourtant nous avions de grands projets pour lui, souvenez-vous :
Nous voulions lui ajouter une fonction drive
.
Mais SchoolBus
hérite de Bus
?!
Oui... Et ?
Du coup, il a déjà à disposition la fonction drive
qui est définie dans Bus
!
Eh oui ! Bien vu ! Mais la fonction drive
de Bus
ne fait que conduire le long de la route sans s'arrêter. Alors que le bus scolaire lui doit s'arrêter à chaque maison, récupérer les enfants et ensuite s'arrêter à l'école.
On a qu'à changer la méthode drive directement dans Bus
.
Oui, mais ce serait un peu faux. Un bus normal ne s'arrête pas devant les maisons et ne va pas à l'école.
Alors qu'est-ce qu'on fait ?
Et bien on utilise l'override !
L'overquoi ?
L'override est une technique qui permet à une classe fille de réécrire une méthode de la classe mère.
Imaginons que la méthode drive
est un DVD sur lequel se trouve l'épisode 4 de Star Wars. Il existe deux façons de faire l'override :
Soit on grave sur le DVD l'épisode 3 (avant) et / ou l'épisode 5 (après) en plus de l'épisode 4.
Soit on efface tout et on met Bambi.
Autrement dit l'override permet à une classe fille de compléter l'implémentation d'une méthode la classe mère ou de la réécrire complètement. Dans les deux cas, comment fait-on ?
On utilise tout simplement le mot-clé override
. Regardons ça avec un exemple. Prenons la classe Animal
suivante :
class Animal {
func saluer() {
print("Bonjour")
}
func seDécrire() {
print("Je suis un animal.")
}
}
Maintenant prenons une classe fille Chien
:
class Chien: Animal {
}
Pour redéfinir les méthodes, il me faut rajouter le mot-clé override
avant ma fonction :
class Chien: Animal {
override func saluer() {
print("Wouf !")
}
override func seDécrire() {
super.seDécrire()
print("Et pas n'importe lequel : un chien !")
}
}
Voyons un peu ce que j'ai fait ici. J'ai modifié la méthode saluer
. Désormais elle n'affiche plus "Bonjour", mais "Wouf !". La méthode a été entièrement modifiée, on ne réutilise rien de la méthode originale. En revanche, dans la méthode seDécrire
, j'appelle la méthode seDécrire
de la classe Animal
en utilisant le mot clé super
comme pour l'initialisation de tout à l'heure. Ensuite, je complète la méthode en rajoutant "Et pas n'importe lequel : un chien !". Du coup, si j'écris :
let unChien = Chien()
unChien.seDécrire()
La console affiche :
Je suis un animal. Et pas n'importe lequel : un chien !
Exercices
Ce que nous avons appris dans ce chapitre va vous permettre d'améliorer notre programme !
Exercice 1
En vous inspirant de la fonction createStraightRoad
, créez une fonction createRoadToSchool
qui permet de créer une route ayant les caractéristiques suivantes :
Une longueur de route de 30
Toutes les 7 sections, une section contient une maison
La dernière section contient une école Pour cet exercice, vous utiliserez les classes
HomeRoadSection
etSchoolRoadSection
que nous avons ajoutées dans ce chapitre.
// Ne regardez pas la correction
static func createRoadToSchool() -> Road {
let road = Road(length: 0)
for i in 0..<30 {
if i%7 == 1 {
road.sections.append(HomeRoadSection(children: 2))
} else {
road.sections.append(RoadSection(type: .plain))
}
}
road.sections.append(SchoolRoadSection())
return road
}
Exercice 2
En utilisant la technique de l'override, vous implémenterez la méthode drive
de la classe SchoolBus
. Le bus doit marquer un arrêt à toutes les maisons et à l'école.
// Ne regardez pas la correction
override func drive(road: Road) {
for section in road.sections {
switch section.type {
case .standard:
moveForward()
case .home:
stop()
moveForward()
case .school:
stop()
}
}
}
Exercice 3
Houston... ?
You are not signed in
Sign in to access coding exercises and test your new skills.
En résumé
Le mot-clé
super
permet d'accéder dans une classe fille à l'implémentation d'une méthode ou d'une initialisation de la classe mère.Le mot-clé
override
permet de modifier dans une classe fille une méthode définie dans une classe mère soit en la complétant soit en la redéfinissant complètement.