Quelles sont les méthodes d'usine statiques?

261

Qu'est-ce qu'une méthode "usine statique"?

freddiefujiwara
la source
Une autre méthode d'usine statique utilise l'injection de dépendances.
CMCDragonkai
1
@ThangPham La réponse de Jason Owen est erronée car elle prétend parler du modèle de méthode d'usine, qui est très différent du modèle de méthode d'usine statique dont il parle réellement. Donc, bien qu'il réponde bien à la vraie question, je ne pense pas qu'il puisse être accepté dans son état actuel, car il apporte un modèle sans rapport et augmente la confusion déjà incroyablement courante à propos de la différence entre les deux modèles.
Theodore Murdock
@CMCDragonkai Je pense que l'injection de dépendances et l'usine statique sont différentes. Une fabrique statique peut être requise même en cas d'injection de dépendances pour que les dépendances instanciées soient injectées.
Karan Khanna

Réponses:

126

Nous évitons de fournir un accès direct aux connexions à la base de données car elles sont gourmandes en ressources. Nous utilisons donc une méthode d'usine statique getDbConnectionqui crée une connexion si nous sommes en dessous de la limite. Sinon, il essaie de fournir une connexion "de rechange", échouant avec une exception s'il n'y en a pas.

public class DbConnection{
   private static final int MAX_CONNS = 100;
   private static int totalConnections = 0;

   private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();

   private DbConnection(){
     // ...
     totalConnections++;
   }

   public static DbConnection getDbConnection(){

     if(totalConnections < MAX_CONNS){
       return new DbConnection();

     }else if(availableConnections.size() > 0){
         DbConnection dbc = availableConnections.iterator().next();
         availableConnections.remove(dbc);
         return dbc;

     }else {
         throw new NoDbConnections();
     }
   }

   public static void returnDbConnection(DbConnection dbc){
     availableConnections.add(dbc);
     //...
   }
}
Matthew Flaschen
la source
si je comprends bien, pouvez-vous ajouter availableConnections.add (db) à la méthode returnDbConnection (DbConnection db)?
Haifeng Zhang
@haifzhan, ce n'est pas vraiment destiné à être complet, mais d'accord.
Matthew Flaschen
@MatthewFlaschen devrait également le totalConnections être décrémenté pendant le retour de la connexion?
pierre à rouler
@Sridhar, non, c'est le nombre de connexions qui existent (suivies pour que plus de MAX_CONNS ne soient pas créées), pas le nombre qui circule.
Matthew Flaschen
@MatthewFlaschen votre méthode sera capturée par sonarcube comme bloqueur de bogues si DbConnection est Closeable.
Awan Biru
477

Le modèle de méthode d'usine statique est un moyen d'encapsuler la création d'objets. Sans une méthode de fabrication, vous appelez simplement de la classe constructeur directement: Foo x = new Foo(). Avec ce modèle, vous à la place appeler la méthode usine: Foo x = Foo.create(). Les constructeurs sont marqués comme privés, ils ne peuvent donc être appelés que depuis l'intérieur de la classe, et la méthode de fabrique est marquée de staticmanière à pouvoir être appelée sans avoir au préalable un objet.

Il y a quelques avantages à ce modèle. La première est que l'usine peut choisir parmi de nombreuses sous-classes (ou implémenteurs d'une interface) et renvoyer cela. De cette façon, l'appelant peut spécifier le comportement souhaité via des paramètres, sans avoir à connaître ou à comprendre une hiérarchie de classe potentiellement complexe.

Comme Matthew et James l'ont souligné, un autre avantage est le contrôle de l'accès à une ressource limitée telle que les connexions. C'est un moyen d'implémenter des pools d'objets réutilisables - au lieu de construire, d'utiliser et de détruire un objet, si la construction et la destruction sont des processus coûteux, il pourrait être plus judicieux de les construire une fois et de les recycler. La méthode d'usine peut renvoyer un objet instancié existant et inutilisé s'il en a un, ou en construire un si le nombre d'objets est inférieur à un seuil inférieur, ou lever une exception ou retourner nulls'il est supérieur au seuil supérieur.

Selon l'article sur Wikipedia, plusieurs méthodes d'usine permettent également différentes interprétations de types d'arguments similaires. Normalement, le constructeur a le même nom que la classe, ce qui signifie que vous ne pouvez avoir qu'un seul constructeur avec une signature donnée . Les usines ne sont pas si contraintes, ce qui signifie que vous pouvez avoir deux méthodes différentes qui acceptent les mêmes types d'arguments:

Coordinate c = Coordinate.createFromCartesian(double x, double y)

et

Coordinate c = Coordinate.createFromPolar(double distance, double angle)

Cela peut également être utilisé pour améliorer la lisibilité, comme le note Rasmus.

Jason Owen
la source
32
Notez qu'une méthode d'usine statique n'est pas la même que le modèle de méthode d'usine de Design Patterns [Gamma95, p. 107]. La méthode d'usine statique décrite dans cet article n'a pas d'équivalent direct dans les modèles de conception.
Josh Sunshine
Le gain pour moi sur cette réponse est la référence aux objets regroupables. C'est EXACTEMENT comment j'utilise le modèle de méthode d'usine. Des méthodes d'usine sont fournies pour aider à contrôler le cycle de vie d'un objet: «créer» extrait un objet du pool ou crée une nouvelle instance si le pool est vide, «détruire» le renvoie au pool pour une réutilisation future.
MutantXenu
2
Vous devriez vraiment utiliser "modèle de méthode d'usine statique" partout où vous dites "modèle de méthode d'usine" dans ce post, vous utilisez le mauvais terme. En outre, vous créez un lien vers l'article Wikipedia sur un modèle différent de celui dont vous parlez. Le modèle Factory Method aurait probablement dû être appelé le modèle "Factory Interface", car il implique l'utilisation de plusieurs objets d'usine qui implémentent une interface d'usine pour permettre à un seul algorithme de produire ainsi que de travailler avec des instances d'une interface, en acceptant un objet d'usine qui peut produire la sous-classe souhaitée spécifique.
Theodore Murdock
8
Je suis d'accord avec @TheodoreMurdock. Vous utilisez le mauvais terme. Ce dont vous parlez, c'est de la "méthode d'usine statique" de Joshua Bloch, mais vous utilisez le terme "modèle de méthode d'usine" du GoF. Veuillez le modifier pour que les autres personnes ne se méprennent pas.
emeraldhieu
1
Notez que le constructeur n'a pas besoin d'être privé. Une classe peut fournir à la fois des méthodes d'usine statique publique et des constructeurs.
Kevin
171

REMARQUE! "La méthode d'usine statique n'est PAS la même que le modèle de méthode d'usine " (c) Java effectif, Joshua Bloch.

Méthode Factory: "Définissez une interface pour créer un objet, mais laissez les classes qui implémentent l'interface décider de la classe à instancier. La méthode Factory permet à une classe de reporter l'instanciation aux sous-classes" (c) GoF.

"La méthode de fabrique statique est simplement une méthode statique qui renvoie une instance d'une classe." (c) Java effectif, Joshua Bloch. Habituellement, cette méthode se trouve dans une classe particulière.

La différence:

L'idée clé de la méthode d'usine statique est de prendre le contrôle de la création d'objets et de la déléguer du constructeur à la méthode statique. La décision de l'objet à créer est comme dans Abstract Factory prise en dehors de la méthode (dans le cas courant, mais pas toujours). Alors que l'idée clé (!) De la méthode d'usine est de déléguer la décision de l'instance de classe à créer à l'intérieur de la méthode d'usine. Par exemple, l'implémentation Singleton classique est un cas particulier de la méthode d'usine statique. Exemple de méthodes d'usine statique couramment utilisées:

  • valeur de
  • getInstance
  • newInstance
Grygoriy Gonchar
la source
Pouvez-vous me dire la différence entre le nouveau A () et A.newInstance ()? et à l'intérieur de A.newInstance, que devons-nous faire?
Shen
69

La lisibilité peut être améliorée par des méthodes d'usine statiques:

Comparer

public class Foo{
  public Foo(boolean withBar){
    //...
  }
}

//...

// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.

à

public class Foo{
  public static Foo createWithBar(){
    //...
  }

  public static Foo createWithoutBar(){
    //...
  }
}

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();
Rasmus Faber
la source
J'ai donc essayé de mettre en œuvre votre exemple, mais je ne sais pas comment cela fonctionne. Les deux méthodes createWithBar et createWithoutBar sont censées appeler 2 constructeurs privés à l'intérieur de la classe Foo?
Essej
@Baxtex: Oui. Chacun appellera un constructeur privé. Peut-être juste le même: private Foo(boolean withBar){/*..*/} public static Foo createWithBar(){return new Foo(true);} public static Foo createWithoutBar(){return new Foo(false);}
Rasmus Faber
Je pense que ce n'est pas très bien "échelle". Si vous avez trois paramètres ou plus, comment pourriez-vous utiliser cette idée et créer un joli nom pour la méthode?
Dherik
@Dherik: Dans ce cas, vous devriez probablement utiliser le modèle de générateur à la place: new FooBuilder (). WithBar (). WithoutFoo (). WithBaz (). Build ();
Rasmus Faber
21
  • avoir des noms, contrairement aux constructeurs, qui peuvent clarifier le code.
  • vous n'avez pas besoin de créer un nouvel objet à chaque appel - les objets peuvent être mis en cache et réutilisés, si nécessaire.
  • peut renvoyer un sous-type de leur type de retour - en particulier, peut renvoyer un objet dont la classe d'implémentation est inconnue de l'appelant. Il s'agit d'une fonctionnalité très précieuse et largement utilisée dans de nombreux frameworks qui utilisent des interfaces comme type de retour des méthodes d'usine statiques.

depuis http://www.javapractices.com/topic/TopicAction.do?Id=21

soldat.moth
la source
18

Tout se résume à la maintenabilité. La meilleure façon de le dire est chaque fois que vous utilisez le newmot - clé pour créer un objet, vous associez le code que vous écrivez à une implémentation.

Le modèle d'usine vous permet de séparer la façon dont vous créez un objet de ce que vous faites avec l'objet. Lorsque vous créez tous vos objets à l'aide de constructeurs, vous connectez essentiellement le code qui utilise l'objet à cette implémentation. Le code qui utilise votre objet "dépend" de cet objet. Cela peut ne pas sembler être un gros problème en surface, mais lorsque l'objet change (pensez à changer la signature du constructeur ou à sous-classer l'objet), vous devez revenir en arrière et recâbler les choses partout.

Aujourd'hui, les usines ont été largement écartées en faveur de l'utilisation de l'injection de dépendance, car elles nécessitent beaucoup de code de plaque de chaudière qui s'avère un peu difficile à maintenir. L'injection de dépendances est fondamentalement équivalente aux usines mais vous permet de spécifier comment vos objets sont câblés ensemble de manière déclarative (via la configuration ou les annotations).

cwash
la source
3
Voulez-vous dire que les usines ont besoin d'un renflouement? ;)
John Farrell
4
Haha! De nos jours, je pense que nous pourrions tous utiliser un plan de sauvetage ... :)
cwash
11

Si le constructeur d'une classe est privé, vous ne pouvez pas créer un objet pour la classe à l'extérieur de celle-ci.

class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}

Nous ne pouvons pas créer un objet pour la classe ci-dessus à l'extérieur de celui-ci. Vous ne pouvez donc pas accéder à x, y de l'extérieur de la classe. Alors à quoi sert cette classe?
Voici la méthode Answer: FACTORY .
Ajoutez la méthode ci-dessous dans la classe ci-dessus

public static Test getObject(){
  return new Test();
}

Vous pouvez donc maintenant créer un objet pour cette classe depuis l'extérieur de celle-ci. Comme la façon dont ...

Test t = Test.getObject();

Par conséquent, une méthode statique qui renvoie l'objet de la classe en exécutant son constructeur privé est appelée méthode FACTORY
.

Santhosh
la source
1
Pourquoi appelez-vous cela une "solution"? Déclarer un constructeur privé n'est pas un "problème", c'est un modèle de conception.
Ojonugwa Jude Ochalifu
1
Actualisé. Merci quand même
Santhosh
Salut @Santhosh Je me demande pourquoi ne laissez-vous pas le constructeur privé public? Si vous ne voulez pas créer de sous-classe, cela me convient, mais si je n'ai pas l'intention de créer un constructeur privé, avons-nous un avantage par Static Factory Methodrapport au constructeur public?
Shen
9

Je pensais que j'apporterais un peu de lumière à ce post sur ce que je sais. Nous avons largement utilisé cette technique dans notre recent android project. Au lieu de cela, creating objects using new operatorvous pouvez également utiliser static methodpour instancier une classe. Liste des codes:

//instantiating a class using constructor
Vinoth vin = new Vinoth(); 

//instantiating the class using static method
Class Vinoth{
  private Vinoth(){
  }
  // factory method to instantiate the class
  public static Vinoth getInstance(){
    if(someCondition)
        return new Vinoth();
  }
}

Les méthodes statiques prennent en charge la création d'objet conditionnelle : chaque fois que vous appelez un constructeur, un objet est créé, mais vous ne le voudrez peut-être pas. supposons que vous vouliez vérifier une condition seulement alors vous voulez créer un nouvel objet. Vous ne créeriez pas une nouvelle instance de Vinoth à chaque fois, à moins que votre condition ne soit remplie.

Un autre exemple tiré de Java efficace .

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}

Cette méthode traduit une valeur primitive booléenne en une référence d'objet booléen. La Boolean.valueOf(boolean)méthode nous illustre, elle ne crée jamais d'objet. La possibilité de static factory methodsrenvoyer le même objet à partir de répétitions invocationspermet aux classes de maintenir un contrôle strict sur les instances existantes à tout moment.

Static factory methodsest que, contrairement à constructors, ils peuvent retourner un objectde n'importe quel subtypetype de retour. Une application de cette flexibilité est qu'une API peut renvoyer des objets sans rendre leurs classes publiques. Masquer les classes d'implémentation de cette manière conduit à une API très compacte.

Calendar.getInstance () est un excellent exemple pour ce qui précède, il crée en fonction de la localisation d' un BuddhistCalendar, JapaneseImperialCalendarou par un défaut Georgian.

Un autre exemple que je pourrais penser est Singleton pattern, lorsque vous rendez vos constructeurs privés créer une propre getInstanceméthode où vous vous assurez, qu'il n'y a toujours qu'une seule instance disponible.

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}
Thalaivar
la source
4

Une méthode d'usine une méthode qui résume l'instanciation d'un objet. En général, les usines sont utiles lorsque vous savez que vous avez besoin d'une nouvelle instance d'une classe qui implémente une interface mais que vous ne connaissez pas la classe d'implémentation.

Ceci est utile lorsque vous travaillez avec des hiérarchies de classes liées, un bon exemple de ceci serait une boîte à outils GUI. Vous pouvez simplement coder en dur les appels aux constructeurs pour les implémentations concrètes de chaque widget, mais si jamais vous vouliez échanger une boîte à outils pour une autre, vous auriez beaucoup d'endroits à changer. En utilisant une usine, vous réduisez la quantité de code que vous devez modifier.

Bryan Kyle
la source
En supposant que votre usine retourne un type d'interface, et non la classe concrète avec laquelle vous avez affaire.
Bill Lynch
1
Cette réponse concerne le modèle de conception de la méthode d'usine et non les méthodes d'usine statiques. Une méthode d'usine statique est simplement une méthode statique publique qui retourne une instance d'une classe. Voir le chapitre 2 de Java efficace pour plus de détails.
Josh Sunshine
4

L'un des avantages qui découle de la fabrique statique est que cette API peut renvoyer des objets sans rendre leurs classes publiques. Cela conduit à une API très compacte. En java, cela est réalisé par la classe Collections qui cache environ 32 classes, ce qui rend l'API de collection très compacte.

Rakesh Chauhan
la source
2

Une méthode d'usine statique est bonne lorsque vous voulez vous assurer qu'une seule instance va retourner la classe concrète à utiliser.

Par exemple, dans une classe de connexion à une base de données, vous souhaiterez peut-être qu'une seule classe crée la connexion à la base de données, de sorte que si vous décidez de passer de Mysql à Oracle, vous pouvez simplement modifier la logique dans une classe, et le reste de l'application utilisez la nouvelle connexion.

Si vous souhaitez implémenter le regroupement de bases de données, cela se fera également sans affecter le reste de l'application.

Il protège le reste de l'application contre les modifications que vous pouvez apporter à l'usine, ce qui est le but.

La raison pour laquelle elle est statique est que si vous souhaitez garder une trace de certaines ressources limitées (nombre de connexions de socket ou de poignées de fichier), cette classe peut garder une trace du nombre de sorties et de retours, afin de ne pas épuiser le ressource limitée.

James Black
la source
2

L'un des avantages des méthodes de fabrique statique avec constructeur privé (la création d'objets doit avoir été restreinte pour les classes externes pour garantir que les instances ne sont pas créées en externe) est que vous pouvez créer des classes contrôlées par l'instance . Et les classes contrôlées par l'instance garantissent qu'il n'existe pas deux instances distinctes égales ( a.equals (b) si et seulement si a == b ) pendant l'exécution de votre programme, ce qui signifie que vous pouvez vérifier l'égalité des objets avec l' opérateur == au lieu de la méthode equals , selon Effective java.

La capacité des méthodes de fabrique statique à renvoyer le même objet à partir d'appels répétés permet aux classes de maintenir un contrôle strict sur les instances existantes à tout moment. Les classes qui font cela seraient contrôlées par l'instance. Il existe plusieurs raisons d'écrire des classes contrôlées par l'instance. Le contrôle d'instance permet à une classe de garantir qu'il s'agit d'un singleton (élément 3) ou non instanciable (élément 4). En outre, il permet à une classe immuable (article 15) de garantir qu'il n'existe pas deux instances égales: a.equals (b) si et seulement si a == b. Si une classe fait cette garantie, ses clients peuvent utiliser l'opérateur == au lieu de la méthode equals (Object), ce qui peut entraîner une amélioration des performances. Les types d'énumération (article 30) offrent cette garantie.

Extrait de Java efficace, Joshua Bloch (article 1, page 6)

SherlockHomeless
la source
1

statique

Un membre a déclaré avec le mot clé 'statique'.

méthodes d'usine

Méthodes qui créent et renvoient de nouveaux objets.

en Java

Le langage de programmation est pertinent pour la signification de «statique» mais pas pour la définition de «usine».

Marquis de Lorne
la source
Les réponses @Victor n'ont pas besoin de contenir d'arguments. Les faits devraient être suffisants: s'ils sont controversés, ils peuvent être étayés par des arguments ou des citations. Je ne suis pas au courant qu'il y ait quelque chose de controversé ici.
Marquis de Lorne
J'ai déclaré que parce que la réponse était trop courte et ne comprenait vraiment pas bien au premier, au deuxième et au troisième coup d'œil, de toute façon, c'est au PO de demander de nouveau. Peu importe, j'ai changé d'avis et j'essaie de supprimer le downvote, mais je ne peux pas.
Victor
@Victor Définissez «trop court». Parfois, la vraie réponse est simplement «oui», «non», «ni», ni «les deux». «Trop court» est entièrement subjectif. Je ne comprends toujours pas votre commentaire d'origine. Vous n'avez pas besoin d'arguments pour prendre en charge les définitions. Par définition. J'ai modifié ma réponse afin qu'il soit désormais possible de supprimer le downvote.
Marquis de Lorne
Bien sûr, c'est subjectif ... toutes les réponses de stackoverflow sont subjectives, en fait elles sont liées au niveau de connaissances et à la volonté de répondre de l'auteur. Je ne comprends vraiment pas votre réponse, c'était peut-être trop court.
Victor
@Victor Rubbish. Les faits ne sont pas subjectifs, pas plus que les sujets qui peuvent être déduits inférentiellement de faits ou d'axiomes. Par contre, «trop court» est subjectif et je l'ai déjà abordé. Cette réponse est essentiellement la même que celle-ci , que vous n'avez pas commentée. Vos commentaires restent obscurs.
Marquis de Lorne
1

L'implémentation Java contient les classes d'utilitaires java.util.Arrays et java.util.Collections les deux contiennent des méthodes d'usine statiques , des exemples de celle-ci et comment utiliser:

De plus, la classe java.lang.String a de telles méthodes d'usine statiques :

  • String.format(...), String.valueOf(..), String.copyValueOf(...)
Владимир Дворник
la source