Méthode de création statique - avantages et inconvénients par rapport aux constructeurs


11

Quels sont les avantages et les inconvénients d'avoir des méthodes de création d'objets statiques par rapport aux constructeurs?

class Foo {
  private Foo(object arg) { }

  public static Foo Create(object arg) {
    if (!ValidateParam(arg)) { return null; }
    return new Foo(arg);
  }
}

Peu de choses auxquelles je peux penser:

Avantages:

  • Retourne null au lieu de lever une exception (nommez-la TryCreate). Cela peut rendre le code plus concis et plus propre du côté client. Les clients s'attendent rarement à l'échec d'un constructeur.
  • Créez différents types d'objets avec une sémantique claire, par exemple CreatFromName(String name)etCreateFromCsvLine(String csvLine)
  • Peut renvoyer un objet mis en cache si nécessaire, ou une implémentation dérivée.

Les inconvénients:

  • Code moins découvrable, plus difficile à parcourir.
  • Certains modèles, comme la sérialisation ou la réflexion, sont plus difficiles (par exemple Activator<Foo>.CreateInstance())

1
C'est plus lent. Vous devez de toute façon gérer la référence nulle.
Amir Rezaei

1
@Amir Handling null est ( Foo x = Foo.TryCreate(); if (x == null) { ... }). La gestion d'une exception ctor est ( Foo x; try { x = new Foo(); } catch (SomeException e) { ... }). Lors de l'appel d'une méthode normale, je préfère les exceptions aux codes d'erreur, mais avec la création d'objet, cela TryCreatesemble plus propre.
dbkk

Souhaitez-vous effectuer une vérification de type dans votre validation?
Amir Rezaei

En ce qui concerne le deuxième Pro, "Créez différents types d'objets avec une sémantique claire, par exemple CreatFromName (String name) et CreateFromCsvLine (String csvLine)", il serait préférable de créer Nameet de taper CsvLineplutôt que d'exprimer des exigences via des noms de méthode. Cela vous permettrait de surcharger Create. L'utilisation de chaînes pour les deux pourrait être considérée comme une «obsession primitive» (en supposant que vous n'ayez pas fait ce choix pour des raisons de performances connues). Découvrez Object Calisthenics pour une façon amusante d'explorer cela.
bentayloruk

Réponses:


7

Le plus gros inconvénient des « créateurs » statiques est probablement de limiter l'héritage. Si vous ou l'utilisateur de votre bibliothèque dérivez une classe de votre Foo, cela Foo::Create()devient à peu près inutile. Toute logique qui y est définie devra être réécrite à nouveau dans l'héritage Create().

Je suggérerais un compromis: définir un constructeur avec une logique d'initialisation d'objet triviale qui ne tombe jamais en panne / jette, puis définir le ou les créateurs avec la mise en cache, la construction alternative, etc. Cela laisse la possibilité de dériver et vous bénéficiez d'avoir des créateurs pour une classe donnée .


1
En pratique, ce n'est pas vraiment un problème, car la plupart des classes ne sont pas conçues pour être héritées (et doivent donc être scellées / finales). S'il s'avère plus tard que vous souhaitez ouvrir la classe à l'héritage, vous pouvez toujours déplacer toute logique d'initialisation vers un constructeur protégé.
Doval

7

Créer est une méthode d'usine. Lorsque j'en ressens le besoin, j'implémente le modèle Factory et je définis une interface pour représenter le contrat de création de l'objet ainsi qu'une classe d'implémentation, qui est ensuite injectée là où c'est nécessaire. Cela conserve les avantages de déplacer la responsabilité de création hors de la classe, mais évite (ou du moins rend plus évident) les limites de la création d'objets en dehors du constructeur de classe.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.