Quand est-ce une bonne idée d'utiliser des méthodes d'usine dans un objet au lieu d'une classe d'usine ?
Réponses
Trop de publicités?J'aime penser aux motifs de conception en considérant que mes classes sont des "personnes", et que les motifs sont les façons dont les personnes se parlent entre elles.
Donc, pour moi, le modèle de l'usine est comme une agence de recrutement. Vous avez une personne qui a besoin d'un nombre variable de travailleurs. Cette personne peut connaître certaines 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 de recrutement et lui font part de leurs besoins. Maintenant, pour réellement louer quelqu'un, vous devez savoir beaucoup de choses - prestations, vérification de l'éligibilité, etc. Mais la personne qui embauche n'a pas besoin de savoir tout cela - l'agence de recrutement s'en charge.
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 leur création ou de leurs dépendances - il doit seulement fournir les informations qu'il souhaite réellement.
public interface IThingFactory
{
Thing GetThing(string theString);
}
public class ThingFactory : IThingFactory
{
public Thing GetThing(string theString)
{
return new Thing(theString, firstDependency, secondDependency);
}
}
Ainsi, le consommateur de la ThingFactory peut maintenant obtenir une chose, sans avoir à connaître les dépendances de la chose, à l'exception des données de la chaîne qui proviennent du consommateur.
Les méthodes d'usine devraient être considérées comme une alternative aux constructeurs - principalement lorsque les constructeurs ne sont pas assez expressifs, par exemple.
class Foo{
public Foo(bool withBar);
}
n'est pas aussi expressif que :
class Foo{
public static Foo withBar();
public static Foo withoutBar();
}
Les classes d'usine sont utiles lorsque vous avez besoin d'un processus compliqué pour construire l'objet, lorsque la construction nécessite une dépendance que vous ne voulez pas pour la classe actuelle, lorsque vous devez construire différents objets, etc.
Une situation où je trouve personnellement que des classes Factory séparées ont un sens est lorsque l'objet final que vous essayez de créer dépend de plusieurs autres objets. Par exemple, en PHP : Supposons que vous avez un objet Maison, qui possède à son tour un objet Cuisine et un objet Salon, et que l'objet Salon contient également un objet TV.
La méthode la plus simple pour y parvenir est de faire en sorte que chaque objet crée ses enfants avec sa méthode de construction, mais si les propriétés sont relativement imbriquées, lorsque la création de votre maison échoue, vous passerez probablement un certain temps à essayer d'isoler exactement ce qui échoue.
L'alternative est de faire ce qui suit (injection de dépendance, si vous aimez le terme fantaisiste) :
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
Ici, si le processus de création d'une Maison échoue, il n'y a qu'un seul endroit où chercher, mais devoir utiliser ce morceau à chaque fois que l'on veut une nouvelle Maison est loin d'être pratique. Entrez dans les Usines :
class HouseFactory {
public function create() {
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
return $HouseObj;
}
}
$houseFactory = new HouseFactory();
$HouseObj = $houseFactory->create();
Grâce à la fabrique, le processus de création d'une maison est abstrait (en ce sens que vous n'avez pas besoin de créer et de configurer chaque dépendance lorsque vous voulez simplement créer une maison) et en même temps centralisé, ce qui facilite la maintenance. Il y a d'autres raisons pour lesquelles l'utilisation d'usines séparées peut être bénéfique (par exemple la testabilité) mais je trouve que ce cas d'utilisation spécifique illustre le mieux l'utilité des classes d'usine.
Il est important de différencier clairement l'idée derrière l'utilisation de factory ou de la méthode factory. Ces deux méthodes sont destinées à résoudre des problèmes de création d'objets différents et mutuellement exclusifs.
Soyons précis sur la "méthode d'usine" :
Tout d'abord, lorsque vous développez une bibliothèque ou des API qui seront ensuite utilisées pour le développement d'autres applications, la méthode factory est l'un des meilleurs choix pour le modèle de création. La raison en est la suivante, nous savons qu'il faut créer un objet ayant la ou les fonctionnalités requises, mais le type d'objet reste indéterminé ou sera décidé par le passage de paramètres dynamiques. .
Maintenant le point est, approximativement la même chose peut être réalisée en utilisant le modèle de fabrique lui-même mais un énorme inconvénient sera introduit dans le système si le modèle de fabrique sera utilisé pour le problème ci-dessus souligné, c'est que votre logique de création de différents objets (objets de sous-classes) sera spécifique à une condition d'affaires ainsi dans le futur quand vous devez étendre la fonctionnalité de votre bibliothèque pour d'autres plates-formes (dans plus techniquement, vous devez ajouter plus de sous-classes d'interface de base ou de classe abstraite pour que la fabrique renvoie ces objets en plus de ceux existants en fonction d'un paramètre dynamique), vous devrez à chaque fois modifier (étendre) la logique de la classe de fabrique, ce qui sera une opération coûteuse et pas bonne du point de vue de la conception. D'un autre côté, si le modèle "factory method" est utilisé pour effectuer la même chose, il suffit de créer une fonctionnalité supplémentaire (sous classes) et de l'enregistrer dynamiquement par injection, ce qui ne nécessite pas de modification du code de base.
interface Deliverable
{
/*********/
}
abstract class DefaultProducer
{
public void taskToBeDone()
{
Deliverable deliverable = factoryMethodPattern();
}
protected abstract Deliverable factoryMethodPattern();
}
class SpecificDeliverable implements Deliverable
{
/***SPECIFIC TASK CAN BE WRITTEN HERE***/
}
class SpecificProducer extends DefaultProducer
{
protected Deliverable factoryMethodPattern()
{
return new SpecificDeliverable();
}
}
public class MasterApplicationProgram
{
public static void main(String arg[])
{
DefaultProducer defaultProducer = new SpecificProducer();
defaultProducer.taskToBeDone();
}
}
- Réponses précédentes
- Plus de réponses