Ensuite, on veut que nos états puissent modifier la vitesse de la voiture. Par exemple, lorsqu'elle est en feu, alors on veut que la voiture diminue sa vitesse jusqu'à s'arrêter. Alors il faut implémenter des mutateurs dans la classe CarState! Quelle horreur!
ça va ressembler à ceci:
Code:
1 2 3 4 5 6 7 8 9 10
| class CarState
{
protected:
Car* owner;
inline const Direction & GetCarDirection() const { return owner_->direction_; }
inline const double & GetCarSpeed() const { return owner_->speed_; }
inline void SetCarDirection( const Direction & direction ) { owner_->direction_ = direction; }
inline void SetCarSpeed( const Direction & speed) { owner_->speed_ = speed; }
}; |
Déjà c'est super moche, là on est aux portes des enfers. Mais si en plus, on veut gérer d'autres choses lorsqu'on modifie la vitesse de la voiture, comme par exemple envoyer des events au moteur audio, alors ça devient n'importe quoi: on voudra gérer ça dans la classe CarState, mais dès qu'on voudra changer la vitesse d'une autre façon, par exemple sur un event du controller (action du joueur par exemple), alors on est niqué! Dans les flammes de l'enfer! Et on en est arrivé là parce que - et c'est où je voulais en venir - on a pas fait attention à la sémantique:
en donnant l'amitié à la classe CarState, on lui permet de s'occuper de choses dont elle n'a pas à s'occuper.
C'est une erreur classique, et pour généraliser, le problème de l'amitié c'est qu'on effectue un transfert de responsabilité, et de façon assez peu explicite, ce qui ouvre la porte à certaines fenêtres.