2010-01-13 16 views
9

Lorsque vous traitez avec des objets qui nécessitent des données connues uniquement lors de l'exécution, comme un nom d'utilisateur et mot de passe, où doit se produire l'instanciation d'objets: à l'aide de nouveau, dans une usine ou dans un conteneur de DI?Conteneur DI, usine, ou nouveau pour les objets éphémères?

Par exemple, je pouvais new un objet une fois que je les données:

UserCredentials creds = 
    new UserCredentials(dialog.getUsername(), dialog.getPassword()); 

Ou, je pourrais utiliser une usine:

UserCredentials creds = 
    CredentialsFactory.create(dialog.getUsername(), dialog.getPassword()); 

Ou, je pourrais utiliser un fournisseur dans un Conteneur DI (qui dans ce cas serait essentiellement une usine pilotée par paramètre). [Exemple de code omis.]

Il semble à la fois erroné d'utiliser le conteneur DI pour quelque chose de si simple mais il semble également erroné de ne pas l'utiliser au maximum.

Répondre

7

Comme toujours, cela dépend, mais en règle générale, une usine statique comme votre deuxième option est rarement une bonne idée.

new La création d'un objet UserCredential semble être un choix judicieux car la classe UserCredentials ressemble à une classe concrète autonome qui peut être entièrement instanciée avec tous ses invariants à partir du nom d'utilisateur et du mot de passe.

Dans d'autres cas, le type que vous souhaitez créer peut représenter une abstraction en soi. Si tel est le cas, vous ne pouvez pas utiliser le mot-clé new, mais vous devez utiliser un Abstract Factory à la place.

L'utilisation d'une fabrique abstraite est souvent très utile car elle vous permet de composer une instance à partir d'une combinaison de valeurs d'exécution et d'autres dépendances. Voir here pour plus d'informations.

L'utilisation d'un résumé d'usine permet également le test unité car vous pouvez simplement vérifier que la valeur de retour ou de l'état final ou tout ce que vous aimez est lié à la sortie de la Fabrique Abstraite - pour lequel vous pouvez facilement fournir un Test Double parce que c'est ... abstrait.

+0

Je n'avais même pas consciemment pensé à l'usine statique par rapport à l'usine abstraite. Merci pour le commentaire sur la valeur ajoutée à cet égard. –

0

Pour moi, j'utilise DI pour créer un couplage plus lâche entre les objets. Si vos dépendances d'objets sont très affectées par la création d'un objet en utilisant new, je ne vois pas pourquoi vous ne pourriez pas utiliser DI ou la création d'objets relais dans une usine. Cela vous donne plus de contrôle et maintient vos classes couplées.

Cela dépend vraiment de quand et où vous aurez besoin de cet objet et s'il y aura des dépendances inutiles en conséquence.

0

Si vous disposez déjà d'un conteneur de DI mis en place pour votre application utilisez cette approche. Sinon, utilisez une méthode d'usine.

2

Le blog google testing a le numéro a post which tries to answer this question. L'idée de base est que vous pouvez classer chacune de vos classes en tant que «nouveau» ou «injectable», et que c'est juste de «nouveau» les nouveautés.

Je distingue 2 grandes catégories de "newables":

  • valeurs comme int, string, DateTime, etcetera.
  • des entités telles que Customer, Order, Employee, etcetera. Je pense que votre classe UserCredentials appartient à cette catégorie.

Il est important de réaliser que newables peut avoir un comportement (testable). Si vous faites l'erreur de penser que les nouveautés ne devraient pas avoir de comportement ou de tests unitaires, vous obtiendrez l'anti-pattern anemic domain model.

Un effet secondaire d'avoir des «nouveaux» avec un comportement est que ce comportement ne peut pas être éliminé dans les tests unitaires de vos injectables. C'est acceptable; Il est normal d'avoir un couplage fort entre votre modèle de domaine et le reste de votre application.

De plus, les nouveaux produits sont autorisés à connaître les injectables, mais ils ne coopèrent qu'avec eux de manière transitoire. Par exemple, UserCredentials ne doit pas prendre un IUserDatabase en tant qu'argument de constructeur. Au lieu de cela, il peut y avoir une méthode UserCredentials.Verify(IUserDatabase).

edit: Je ne suis pas si sûr de ce que j'ai écrit plus haut. Les entités peuvent également être construites via des usines (injectables) au lieu d'appeler leur constructeur directement. L'implémentation en usine peut alors injecter des choses dans l'entité.

+0

Votre lien "Modèle de domaine anémique" fait référence à l'article "Nouveau ou non nouveau". –

+0

merci, c'est réglé maintenant. –

+0

+1 spécialement pour l'avertissement sur le modèle anémique – NoxArt