Je lis des objets PHP, des modèles et de la pratique . L'auteur essaie de modéliser une leçon dans un collège. L'objectif est d'afficher le type de leçon (conférence ou séminaire), et les frais pour la leçon selon qu'il s'agit d'une leçon horaire ou à prix fixe. La sortie doit donc être
Lesson charge 20. Charge type: hourly rate. Lesson type: seminar.
Lesson charge 30. Charge type: fixed rate. Lesson type: lecture.
lorsque l'entrée est la suivante:
$lessons[] = new Lesson('hourly rate', 4, 'seminar');
$lessons[] = new Lesson('fixed rate', null, 'lecture');
J'ai écrit ceci:
class Lesson {
private $chargeType;
private $duration;
private $lessonType;
public function __construct($chargeType, $duration, $lessonType) {
$this->chargeType = $chargeType;
$this->duration = $duration;
$this->lessonType = $lessonType;
}
public function getChargeType() {
return $this->getChargeType;
}
public function getLessonType() {
return $this->getLessonType;
}
public function cost() {
if($this->chargeType == 'fixed rate') {
return "30";
} else {
return $this->duration * 5;
}
}
}
$lessons[] = new Lesson('hourly rate', 4, 'seminar');
$lessons[] = new Lesson('fixed rate', null, 'lecture');
foreach($lessons as $lesson) {
print "Lesson charge {$lesson->cost()}.";
print " Charge type: {$lesson->getChargeType()}.";
print " Lesson type: {$lesson->getLessonType()}.";
print "<br />";
}
Mais selon le livre, je me trompe (je suis presque sûr que je le suis aussi). Au lieu de cela, l'auteur a donné une grande hiérarchie de classes comme solution. Dans un chapitre précédent, l'auteur a déclaré les «quatre panneaux indicateurs» suivants comme le moment où je devrais envisager de changer la structure de ma classe:
- Duplication de code
- La classe qui en savait trop sur son contexte
- Le cric de tous les métiers - des classes qui essaient de faire beaucoup de choses
- Expressions conditionnelles
Le seul problème que je peux voir, ce sont les déclarations conditionnelles, et cela aussi de manière vague - alors pourquoi refactoriser cela? À votre avis, quels problèmes pourraient survenir à l'avenir que je n'ai pas prévus?
Mise à jour : j'ai oublié de mentionner - c'est la structure de classe que l'auteur a fournie comme solution - le modèle de stratégie :
la source
Réponses:
C'est drôle que le livre ne l'énonce pas clairement, mais la raison pour laquelle il favorise une hiérarchie de classe plutôt que si les instructions à l'intérieur de la même classe est probablement le principe Open / Closed Cette règle de conception logicielle largement connue stipule qu'une classe doit être fermée à modification mais ouvert à l'extension.
Dans votre exemple, l'ajout d'un nouveau type de leçon signifierait changer le code source de la classe Lesson, le rendant fragile et sujet à régression. Si vous aviez une classe de base et un dérivé pour chaque type de leçon, il vous suffirait simplement d'ajouter une autre sous-classe, qui est généralement considérée comme plus propre.
Vous pouvez mettre cette règle dans la section "Déclarations conditionnelles" si vous voulez, mais je considère que le "panneau" est un peu vague. Si les instructions ne sont généralement que des odeurs de code, des symptômes. Ils peuvent résulter d'une grande variété de mauvaises décisions de conception.
la source
Je suppose que ce que le livre vise à enseigner est d'éviter des choses comme:
Mon interprétation du livre est que vous devriez avoir trois classes:
Vous devez ensuite réimplémenter la
cost
fonction sur les deux sous-classes.Mon opinion personnelle
pour des cas simples comme celui-ci: ne le faites pas. Il est étrange que votre livre favorise une hiérarchie de classe plus profonde pour éviter de simples déclarations conditionnelles. De plus, avec votre spécification d'entrée, il
Lesson
devra s'agir d'une usine avec une répartition qui est une instruction conditionnelle. Ainsi, avec la solution livre, vous aurez:C'est plus de complexité sans avantage supplémentaire.
la source
SemesterLesson
,MasterOneWeekLesson
etc. Une classe racine abstraite, ou mieux encore une interface, est définitivement la voie à suivre. Mais lorsque vous n'avez que deux cas, c'est à la discrétion de l'auteur.L'exemple dans le livre est assez étrange. D'après votre question, la déclaration originale est:
ce qui, dans le cadre d'un chapitre sur la POO, signifierait que l'auteur souhaite probablement que vous ayez la structure suivante:
Mais vient ensuite l'entrée que vous avez citée:
c'est-à-dire quelque chose qui s'appelle du code typé chaîne et qui, honnêtement, dans ce contexte lorsque le lecteur est censé apprendre la POO, est horrible.
Cela signifie également que si j'ai raison sur l'intention de l'auteur du livre (c'est-à-dire la création des classes abstraites et héritées que j'ai énumérées ci-dessus), cela conduira à du code dupliqué et assez illisible et laid:
Quant aux "poteaux indicateurs":
Duplication de code
Votre code n'a pas de duplication. Le code que l'auteur attend de vous que vous écriviez le fait.
La classe qui en savait trop sur son contexte
Votre classe passe simplement des chaînes de l'entrée à la sortie et ne sait rien du tout. En revanche, le code attendu peut être critiqué pour en savoir trop.
The Jack of All Trades - Des classes qui essaient de faire beaucoup de choses
Encore une fois, vous ne faites que passer des chaînes, rien de plus.
Expressions conditionnelles
Il y a une instruction conditionnelle dans votre code. Il est lisible et facile à comprendre.
Peut-être, en fait, l'auteur s'attendait à ce que vous écriviez un code beaucoup plus refactorisé que celui avec six classes ci-dessus. Par exemple, vous pouvez utiliser le modèle d'usine pour les leçons et les frais, etc.
Dans ce cas, vous vous retrouverez avec neuf classes, qui seront un parfait exemple de surarchitecture .
Au lieu de cela, vous vous êtes retrouvé avec un code propre et facile à comprendre, qui est dix fois plus court.
la source
Tout d'abord, vous pouvez changer les "nombres magiques" comme 30 et 5 dans la fonction cost () en variables plus significatives :)
Et pour être honnête, je pense que vous ne devriez pas vous en préoccuper. Lorsque vous devrez changer de classe, vous le changerez. Essayez d'abord de créer de la valeur, puis passez à la refactorisation.
Et pourquoi pensez-vous que vous vous trompez? Ce cours n'est-il pas "assez bon" pour vous? Pourquoi vous inquiétez-vous pour un livre;)
la source
Il n'est absolument pas nécessaire d'implémenter des classes supplémentaires. Vous avez un petit
MAGIC_NUMBER
problème dans votrecost()
fonction, mais c'est tout. Tout le reste est une sur-ingénierie massive. Cependant, il est malheureusement courant de donner de très mauvais conseils - Circle hérite de Shape, par exemple. Il n'est certainement pas efficace de dériver une classe pour l'héritage simple d'une fonction. Vous pouvez utiliser une approche fonctionnelle pour le personnaliser à la place.la source