Class.newInstance () suit-il le modèle de conception «Fabrique abstraite»?

J’ai commencé à lire “Effective Java” de Joshua Bloch (deuxième édition). Lors de la lecture de l’élément 2 ( considérez un générateur confronté à de nombreux parameters de constructeur ), il existe une instruction particulière que l’auteur crée par la méthode Class.newInstance () . Plus précisément, l’auteur dit que

L’implémentation traditionnelle de Abstract Factory en Java a été l’object “Class”, la méthode “newInstance” jouant le rôle de la méthode “build”.

Cette partie m’a un peu troublé – si j’ai bien compris le modèle de conception d’usine abstraite, c’est qu’il est utilisé pour représenter une usine d’usines. À mon avis, la méthode Class.newInstance () est plus proche de la philosophie de codage de la “méthode d’usine statique” (qui est d’ailleurs le premier élément du même livre).

Des pensées, quelqu’un? Je me suis préparé avec acharnement à quelques entrevues difficiles et j’apprécierais vraiment si mes bases étaient solides avant de comparaître pour de telles entrevues.

Merci.

Voici mon avis.

Tout d’abord, le motif Abstract Factory n’est pas destiné à être une fabrique d’usines. L’aspect essentiel de ce modèle est qu’il existe une interface accessible avec une implémentation d’usine sous-jacente (probablement inaccessible) grâce à laquelle vous pouvez obtenir des interfaces accessibles d’implémentations d’objects (probablement inaccessibles). Je sais, est un long jeu de mots méchant qui explique comment je comprends certaines des conditions d’applicabilité de ce modèle dans le livre de Gamma:

  • un système doit être indépendant de la manière dont ses produits sont créés, composés et représentés
  • vous voulez fournir une bibliothèque de classe de produits et révéler uniquement leurs interfaces, et non leurs implémentations.

À la fin, vous obtenez des objects, pas des usines.

Deuxièmement, je ne ferais pas de relations 1: 1 entre les concepts de modèle et les mots-clés de langage. “Abstract Factory” ne traduit pas nécessairement toujours dans la abstract class Java ou interface constructions d’ interface . Vous pouvez toujours avoir une classe régulière, extensible et instanciable qui représente une “fabrique abstraite” à condition de garantir que le code client est indépendant de la fabrique sous-jacente et des implémentations d’object. C’est le cas de java.lang.Class , qui n’est ni une interface abstraite, mais qui newInstance() la mise en oeuvre du constructeur sans paramètre du type qu’elle représente par le biais de la méthode newInstance() . C’est probablement plus clair si vous l’utilisez comme:

 Object o = Class.forName(type).newInstance(); 

Class joue “L’abstrait Factory” et Object joue le “Produit abstrait” pour l’implémentation de type.

Enfin, newInstance() n’est pas une méthode fabrique statique, car ce modèle est destiné à renvoyer des instances de la classe sur laquelle il est implémenté. newInstance() ne renvoie pas d’instances de Class ni de sous- Class . Il retourne des instances du type qu’il représente. Ce n’est pas non plus une “méthode d’usine”, comme le dit Bloch dans son livre.

Je ne pense pas que quoi que ce soit qui puisse suggérer que Abstract Factory soit “une fabrique d’usines”. Un AbstractFactory ne crée pas d’usines qui créent des T s, il le crée directement.

L’idée qu’il est abstrait est de permettre à la logique de créer T d’être injectée. Ainsi, par exemple, vous pourriez avoir:

 public interface ConnectionFactory { Connection newConnection(); } //passed to your object normally: public class RealConnectionFactory implements ConnectionFactory { //... } //passed to your object when unit testing: public class FakeConnectionFactory implements ConnectionFactory { //... } //... public class MyDao { public MyDao(ConnectionFactory connectionFactory) { this.conn = connectionFactory.newConnection(); } } 

Dans ce cas, ConnectionFactory crée Connection s, mais est abstrait car il s’agit d’une interface.

Je suis plutôt d’accord avec vous pour dire que Class.newInstance() n’est pas un exemple canonique d’une fabrique abstraite, car Class n’est pas abstrait et ne peut en fait être étendu . Vous ne pouvez pas demander une Class et une implémentation initialise la nouvelle valeur à 1 et une autre initialise la nouvelle valeur à 7 .

Vous pouvez cependant étirer les choses en disant quelque chose comme Class Class est une fabrique abstraite de InputStream s, avec des implémentations concrètes de Class et de Class . Cependant, ce n’est pas le sens traditionnel du mot “abstrait” (il n’ya toujours qu’une classe: Class ).

Mais même dans ce cas, il est inutile en tant que fabrique abstraite, car vous implémentez une nouvelle version concrète de la “fabrique” en créant une nouvelle classe qui étend InputStream . Ce n’est pas ce à quoi les usines abstraites sont destinées.

À mon avis, il fait référence à un code tel que:

 Integer.class.newInstance(); 

Class est la fabrique abstraite. Cela est devenu concret lorsque vous avez passé le paramètre type, par exemple Integer . Vous avez ensuite appelé le “constructeur”, newInstance() .