Pourquoi le modèle de conception de méthode d'usine est-il plus utile que d'avoir des classes et de les appeler individuellement?

32

À partir des modèles de conception "Gang of Four", il y a la méthode Factory:

class Factory(product)
  case product
  when a
    new A
  when b
    new B
  when c
    new C
end

new Factory(a)

Pourquoi est - ce plus utile que d' avoir trois classes, a, bet cet les appeler individuellement?

alt
la source
1
Que voulez-vous dire précisément? Pourquoi ne pas instancier les trois? C'est ça que tu veux dire?
Neil
1
@Neil Non, dans le modèle d'usine, toutes les classes existent en tant que frères et sœurs. Pourquoi appeler l'usine pour accéder indirectement aux classes a, b, c?
alt
3
cela ne ressemble pas vraiment au modèle de méthode d'usine, si ce n'est plus proche de l'usine abstraite
jk.
2
Parce qu'au moment de la conception, vous ne savez pas laquelle des 3 classes vous devez instancier.
MrWhite
2
@jk: Non, ce n'est vraiment pas le cas. programmers.stackexchange.com/questions/81838/…
pdr

Réponses:

54

Parce que votre exemple n'est pas assez compliqué. Pour un scénario aussi simple, il n'est même pas logique d'utiliser un modèle avancé.

Mais si vous devez en savoir plus que le produit pour construire A, B ou C, et que vous ne pouvez pas avoir un accès direct à cette connaissance, alors c'est utile. Ensuite, vous utilisez l'usine pour servir de centre de connaissances pour la production des objets nécessaires.

Peut-être que ces objets ont besoin d'une référence à un objet X, que l'usine peut fournir, mais votre code à l'endroit où vous voulez construire A, B ou C ne peut pas ou ne devrait pas avoir accès à X. Peut-être quand vous avez X vous créez A et B mais si vous avez un type Y, vous créez C.

Considérez également que certains objets peuvent nécessiter 20 dépendances pour être créés; alors quoi? Aller à la recherche de ces dépendances dans un endroit où elles ne devraient pas être accessibles pourrait être problématique.

Mateusz
la source
13
+1 pour indiquer clairement que le modèle d'usine n'est pas toujours la meilleure approche.
Neil
1
Parce que votre exemple n'est pas assez compliqué. Pour un scénario aussi simple, il n'est même pas logique d'utiliser un modèle avancé. Que feriez-vous dans ce cas? Inline la construction conditionnelle?
pdr
Il peut s'agir simplement d'une méthode qui prend le produit et retourne ce dont vous avez besoin pour le rendre réutilisable, il n'a donc pas besoin d'être en ligne. Si une telle méthode se développe en quelque chose de plus grand, ou est utilisée dans plusieurs autres classes, vous pouvez la refactoriser en classe différente.
Mateusz
Le motif est appelé méthode d'usine pour une raison. La méthode n'a pas besoin d'être dans une classe différente pour être une méthode d'usine (bien qu'elle le soit souvent).
pdr
J'ai raté la "méthode", donc vous avez raison monsieur.
Mateusz
23

Un modèle d'usine est généralement plus complexe que cela. Une usine décide de certains critères quelle instance créer / retourner. Au lieu de cela, lorsque vous n'utilisez pas l'usine, ce code sera utilisé à plusieurs reprises à plusieurs endroits dans votre code.

À titre d'exemple, considérez ce qui suit: vous devez charger des données à partir d'une base de données, mais vous avez une base de données centrale pour l'intégration avec beaucoup de données, et une plus petite en mémoire sur chaque dev-PC. Dans votre code, vous demandez à une fabrique d'obtenir un descripteur de base de données et la fabrique en renvoie une en fonction, par exemple, d'un fichier de configuration.

Andy
la source
20

Le modèle Factory Method résume le processus de prise de décision de la classe appelante. Cela présente plusieurs avantages:

Réutilisation. Si je veux instancier à de nombreux endroits, je n'ai pas à répéter ma condition, donc quand je viens d'ajouter une nouvelle classe, je ne risque pas d'en manquer une.

Testabilité unitaire. Je peux écrire 3 tests pour la fabrique, pour m'assurer qu'elle retourne les types corrects dans les conditions correctes, alors ma classe appelante n'a besoin que d'être testée pour voir si elle appelle la fabrique puis les méthodes requises sur la classe retournée. Il ne doit rien savoir de l'implémentation de l'usine elle-même ni des classes concrètes.

Extensibilité. Lorsque quelqu'un décide que nous devons ajouter une nouvelle classe D à cette usine, aucun code appelant, ni tests unitaires ni implémentation, n'a jamais besoin d'être dit. Nous créons simplement une nouvelle classe D et étendons notre méthode d'usine. Telle est la définition même du principe ouvert-fermé .

Vous pouvez même créer une nouvelle classe d'usine et les rendre remplaçables à chaud, si la situation l'exige - par exemple, si vous voulez pouvoir activer et désactiver la classe D pendant le test. Je n'ai rencontré cette situation qu'une seule fois, mais c'était extrêmement utile.

Comme cela a été dit, le Factory Pattern n'est pas toujours le chemin à parcourir. Mais, partout où vous voyez une instanciation conditionnelle, vous devriez y réfléchir un instant.

pdr
la source
14

Les principaux avantages du modèle Factory sont doubles:

  1. Les lieux qui nécessitent une implémentation du produit n'ont pas besoin de savoir comment en construire un. L'usine détient cette information.

    Voulez-vous savoir quels arguments passer au constructeur particulier? Ou quelles dépendances devez-vous injecter? Ou comment enregistrer la classe d'implémentation dans la base de données une fois qu'elle est entièrement configurée? Non? Laissez l'usine s'occuper de tout ça.

  2. Les endroits qui nécessitent une implémentation du produit n'ont pas besoin de savoir au moment de la description du module (c'est-à-dire au moment de la compilation) quel est le nom de la classe d'implémentation.

    Ainsi, an'a pas besoin d'avoir quoi que ce soit à voir avec A; le «quoi construire» peut être décrit en fonction des propriétés non fonctionnelles souhaitées, et pas seulement du nom. C'est beaucoup plus flexible.

L'inconvénient est que lorsque vous savez quoi faire et comment le faire, vous obtenez plus de complexité lorsque vous utilisez une usine. La solution est simple: n'utilisez pas une usine quand cela n'a pas de sens!

Donal Fellows
la source
2

Je voudrais penser aux modèles de conception en termes de classes en tant que «personnes», et les modèles sont des façons dont les gens se parlent.

Donc, pour moi, le modèle d'usine est comme une agence d'embauche. Vous avez quelqu'un qui aura besoin d'un nombre variable de travailleurs. Cette personne peut connaître les informations dont elle a besoin chez les personnes qu'elle embauche, mais c'est tout.

Ainsi, lorsqu'ils ont besoin d'un nouvel employé, ils appellent l'agence d'embauche et leur disent ce dont ils ont besoin. Maintenant, pour embaucher quelqu'un, vous devez en savoir beaucoup de choses - avantages sociaux, vérification de l'admissibilité, etc. Mais la personne qui embauche n'a pas besoin de savoir tout cela - l'agence d'embauche s'occupe de tout cela.

De la même manière, l'utilisation d'une usine permet au consommateur de créer de nouveaux objets sans avoir à connaître les détails de la façon dont ils ont été créés, ni quelles sont leurs dépendances - ils n'ont qu'à fournir les informations qu'ils souhaitent réellement.

Courtoisie

Premraj
la source
1

Le modèle Factory est le modèle de conception le plus utilisé et le plus abusé.

J'ai rencontré de nombreux cas où une classe Factory est codée lorsqu'un simple constructeur serait adéquat.

N'utilisez pas une classe d'usine à moins que: -

  • Vous dépendez d'une ressource externe mais vous ne savez pas encore exactement laquelle.
  • La construction coûte cher et vous voulez construire une fois et réutiliser plusieurs fois.
  • La construction d'une nouvelle instance dépend des instances qui ont déjà été construites (par exemple, Votre ne peut avoir que cinq connexions, ou vous devez utiliser un identifiant de connexion numéro un de plus que le dernier numéro utilisé).
James Anderson
la source
0

Utilisez la méthode Factory lors de l'instanciation d'une sous-classe et le code client n'est pas censé être responsable de la décision de la sous-classe particulière à instancier.

Il est utile car il vous évite d'avoir à modifier le code client lorsque vous devez changer la classe à instancier. La modification du code existant est une mauvaise pratique car elle est généralement sujette aux erreurs.

Un exemple serait d'avoir des sous-classes, où chacune trie les données dans l'ordre croissant, mais d'une manière différente. Chaque voie est optimale pour un type particulier de données. Ex: données partiellement triées, données qui sont des nombres, etc. Le code client est une classe qui ne gère que l'impression des données. Avoir du code qui décide quelle classe de tri est instanciée dans la classe client en ferait une classe complexe. En d'autres termes, avoir plus d'une responsabilité, dans ce cas, décider quelle classe de tri est optimale et imprimer les données. En plaçant le code qui décide quelle classe de tri est instanciée dans une classe Factory, il sépare les problèmes afin que vous n'ayez pas besoin de changer la classe client à chaque fois que vous devez changer la sous-classe de tri qui est instanciée.

C'est une façon de couvrir votre cul, si vous pouvez prévoir vos changements d'auto-évaluation dans la ligne de la façon dont ou quelle classe sera instanciée, les classes d'usine ont du sens à utiliser. Cela permet de garder vos classes concentrées sur leur seule responsabilité et, par conséquent, vous évite d'avoir à modifier le code existant qui n'est pas lié.

kiwicomb123
la source