Les deux réponses actuelles semblent ne frapper que partiellement la cible, et elles se concentrent sur des exemples qui brouillent l'idée de base. Ce n'est pas non plus (uniquement) un principe de POO mais un principe de conception de logiciel en général.
La chose qui "varie" dans cette phrase est le code. Christophe a raison de dire que c'est généralement quelque chose qui peut varier, c'est-à-dire que vous l' anticipez souvent . Le but est de vous protéger des modifications futures du code. Ceci est étroitement lié à la programmation sur une interface . Cependant, Christophe a tort de limiter cela aux "détails d'implémentation". En fait, la valeur de ces conseils est souvent due à des changements dans les exigences .
Ceci n'est qu'indirectement lié à l'encapsulation de l'état, ce à quoi je pense que David Arno pense. Ce conseil ne suggère pas toujours (mais souvent) un état d'encapsulation, et ce conseil s'applique également aux objets immuables. En fait, le simple fait de nommer des constantes est une forme (très basique) d'encapsuler ce qui varie.
CandiedOrange confond explicitement «ce qui varie» avec «détails». Ce n'est que partiellement correct. Je suis d'accord que tout code qui varie est des "détails" dans un certain sens, mais un "détail" ne peut pas varier (sauf si vous définissez des "détails" pour rendre cela tautologique). Il peut y avoir des raisons d'encapsuler des détails non variables, mais ce dicton n'en est pas un. En gros, si vous étiez très confiant que "chien", "chat" et "canard" seraient les seuls types avec lesquels vous auriez besoin de traiter, alors ce dicton ne suggère pas le refactoring effectué par CandiedOrange.
Casting l'exemple de CandiedOrange dans un contexte différent, supposons que nous avons un langage procédural comme C. Si j'ai du code qui contient:
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
Je peux raisonnablement m'attendre à ce que ce morceau de code change à l'avenir. Je peux "l'encapsuler" simplement en définissant une nouvelle procédure:
void speak(pet) {
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
}
et en utilisant cette nouvelle procédure au lieu du bloc de code (c'est-à-dire une refactorisation de "méthode d'extraction"). À ce stade, l'ajout d'un type "vache" ou autre ne nécessite que la mise à jour de la speak
procédure. Bien sûr, dans une langue OO, vous pouvez plutôt tirer parti de la répartition dynamique comme le mentionne la réponse de CandiedOrange. Cela se produira naturellement si vous accédez pet
via une interface. L'élimination de la logique conditionnelle via la répartition dynamique est une préoccupation orthogonale qui faisait partie de la raison pour laquelle j'ai fait ce rendu procédural. Je tiens également à souligner que cela ne nécessite pas de fonctionnalités particulières à la POO. Même dans un langage OO, encapsuler ce qui varie ne signifie pas nécessairement qu'une nouvelle classe ou interface doit être créée.
À titre d'exemple plus archétypal (qui est plus proche mais pas tout à fait OO), disons que nous voulons supprimer les doublons d'une liste. Supposons que nous l'implémentions en parcourant la liste en gardant une trace des éléments que nous avons vus jusqu'à présent dans une autre liste et en supprimant tous les éléments que nous avons vus. Il est raisonnable de supposer que nous pouvons vouloir changer la façon dont nous gardons la trace des éléments vus pour, au moins, pour des raisons de performances. Le dicton pour encapsuler ce qui varie suggère que nous devrions construire un type de données abstrait pour représenter l'ensemble des éléments vus. Notre algorithme est maintenant défini par rapport à ce type de données Set abstrait, et si nous décidons de passer à un arbre de recherche binaire, notre algorithme n'a pas besoin de changer ou de prendre soin. Dans un langage OO, nous pouvons utiliser une classe ou une interface pour capturer ce type de données abstrait. Dans une langue comme SML / O '
Pour un exemple axé sur les exigences, supposons que vous devez valider un champ en ce qui concerne une logique métier. Bien que vous puissiez avoir des exigences spécifiques maintenant, vous soupçonnez fortement qu'elles évolueront. Vous pouvez encapsuler la logique actuelle dans sa propre procédure / fonction / règle / classe.
Bien qu'il s'agisse d'une préoccupation orthogonale qui ne fait pas partie de "l'encapsulation de ce qui varie", il est souvent naturel d'abstraire, c'est-à-dire de paramétrer, la logique désormais encapsulée. Cela conduit généralement à un code plus flexible et permet à la logique d'être modifiée en remplaçant dans une implémentation alternative plutôt qu'en modifiant la logique encapsulée.