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()
)
design-patterns
dbkk
la source
la source
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, celaTryCreate
semble plus propre.Name
et de taperCsvLine
plutô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.Réponses:
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
, celaFoo::Create()
devient à peu près inutile. Toute logique qui y est définie devra être réécrite à nouveau dans l'héritageCreate()
.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 .
la source
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.
la source