L'injection de dépendance lorsque la classe créée a besoin également des valeurs d'exécution?
-
29-09-2019 - |
Question
Supposons que vous divisez vos systèmes en valeur des objets et des objets services (comme suggéré dans "Growing Object-Oriented Software, guidée par des tests". Appelle Misko Hevery ces "newables" et "" injectables.
Qu'est-ce qui se passe quand l'un de vos objets valeur soudainement besoin d'accéder à un service à mettre en œuvre des méthodes de il?
Disons que vous avez un bel objet de valeur simple. Il est immuable, détient quelques bits d'information et qui est à ce sujet. Disons que nous utilisons quelque chose comme ceci:
CreditCard card = new CreditCard("4111-1111-1111-1111", "07/10");
if (card.isValid())
{
// do stuff
}
else
{
// don't do stuff
}
Jusqu'à présent, si bon. isValid()
met en œuvre un algorithme de vérification des chiffres du numéro de carte et retourne true / false.
Maintenant, disons que je souhaite améliorer le système en validant la date d'expiration contre l'heure actuelle. Comment proposeriez-vous cela se fait sans casser l'objet Valeur / objet Service paradim? Je voudrais cette classe pour continuer à être testable.
-
CreditCard
a maintenant une dépendance, mais à cause de la façon dont il est créé, il ne peut pas être injecté, si l'injection de dépendance est dehors. - La classe
CreditCard
ne doit pas être interpellent singletons (je suis de la position que l'accès global à un Singleton est une mauvaise pratique) - Mettre le comportement
CreditCardVerificationService.validateCard()
signifie tout le code existant doit être revisité. La mise en œuvre de isValid () est FUITES.
Je sais qu'il ya des choses qui peuvent être faites pour se déplacer, mais quelle est la manière la plus propre?
La solution
Je dirais que ce n'est pas le travail d'un objet CreditCard à quoi que ce soit validate. Une usine validerait les chiffres de contrôle pour vous assurer qu'il est instancié une carte conforme, tandis qu'un service de vérification validerait la carte pour l'expiration / $ limite.
Autres conseils
Je serais tenté de dire que CreditCard
est pas un objet de valeur.
De la C2 wiki :
Des exemples d'objets de valeur sont des choses comme des chiffres, des dates, des fonds et cordes. Habituellement, ils sont petits les objets qui sont utilisés assez largement. Leur identité est basée sur leur état plutôt que sur leur identité d'objet. De cette façon, vous pouvez avoir plusieurs copies du même objet de valeur théorique.
Un objet de valeur est un BusinessObject / ReferenceObject. UNE BusinessObject / ReferenceObject est quelque chose que vous trouvez dans le monde, alors que un ValueObject est une mesure ou description de quelque chose.
Si CreditCardNumber
pourrait être un objet de valeur, CreditCard
ressemble plus à un objet métier qui contient une certaine logique métier, par exemple validation.
Je généralement une valeur objet, objet de service et d'affaires. Je ne sais pas « Growing logiciel orienté objet », mais vous limiter à seulement une valeur d'objets et de service me semble étrange.
J'appellerait CreditCard
une entité plutôt que objet de valeur , car il est susceptible d'être persistants et ont une identité unique.
Quoi qu'il en soit, il devrait être parfaitement bien pour une classe d'entité à utiliser des classes de service. Si les mises en œuvre de ces services ne doivent pas nécessairement être sélectionné lors de l'exécution en fonction de la configuration externe, alors je voudrais simplement instancier et utiliser la classe de service souhaitée à l'intérieur de la méthode client. Contrairement à ce que certains pensent, cela ne fait pas obstacle aux tests unitaires, comme un outil moqueur peut être utilisé pour l'isolement.
Si la mise en œuvre de services Finalité doivent être sélectionnées lors de l'exécution, que Service de localisation pourrait être utilisé. Ce modèle peut fournir un soutien direct pour se moquant / trucage, sans la nécessité d'un outil spécialisé se moquant. Utilisation d'un cadre de DI soutenir l'injection en objets « newed » serait une autre alternative.