Pourquoi avons-nous besoin d'un modèle de conception d'usine abstraite?

124

La plupart de la définition dit:

Une fabrique abstraite fournit une interface pour créer des familles d'objets associés sans spécifier leurs classes concrètes

Quelle est l'utilisation de Abstract Factory Pattern car nous pouvons réaliser la tâche en créant un objet de la classe concrète elle-même. Pourquoi avons-nous une méthode d'usine qui crée un objet de la classe Concrete?

Veuillez me fournir un exemple concret où je dois implémenter le modèle abstractFactory?

Amit
la source

Réponses:

218

Abstract Factory est un modèle de conception très central pour l' injection de dépendances (DI). Voici une liste de questions Stack Overflow pour lesquelles l'application de Abstract Factory a été acceptée comme solution.

Au meilleur de ma compréhension, ces questions représentent des préoccupations ou des problèmes réels que les gens ont eu, donc cela devrait vous aider à commencer avec des exemples réels:

Mark Seemann
la source
6
Tous ces exemples décrivent le modèle de méthode d'usine, car ils renvoient tous une seule interface de produit. Aucun de ceux-ci n'est un modèle de fabrique abstraite, car aucun d'entre eux ne produit une famille d'interfaces de produits connexes.
jaco0646
32
Dans l'intérêt d'une divulgation complète, l'auteur de cette réponse aurait dû indiquer clairement qu'il est également l'auteur de chacune des réponses liées; donc cette liste n'est PAS un échantillon représentatif de la communauté SO.
jaco0646
1
@ jaco0646 IIRC, le modèle de méthode d'usine est une spécialisation du modèle de méthode de modèle , qui repose sur l'héritage. Je me trompe peut-être, car je voyage actuellement et je n'ai pas mon livre GoF avec moi. Qu'entendez-vous par «aucun d'entre eux ne produit une famille d'interfaces de produits connexes»?
Mark Seemann
1
L'indice le plus simple qui indique qu'une usine n'est pas conforme au modèle d'usine abstraite est de compter les produits abstraits que l'usine fabrique (j'ai utilisé le terme «interfaces de produit» à la place de «produits abstraits» pour éviter la surutilisation du mot «abstrait») . Une usine qui produit un seul produit abstrait ne peut pas être une usine abstraite, car par définition, Abstract Factory fabrique une famille de produits connexes . Il est essentiel de noter que cette famille ne fait pas référence à différentes implémentations d'une interface, mais plutôt à des produits avec différentes interfaces associées.
jaco0646
1
Voici un exemple oodesign.com/abstract-factory-pattern.html . C'est pour cela que le modèle de fabrique abstraite a été créé à l'origine.
user2802557
23

Un exemple concret d'utilisation du modèle Abstract Factory est de fournir un accès aux données à deux sources de données différentes. Supposons que votre application prend en charge différents magasins de données. (par exemple une base de données SQL et un fichier XML). Vous disposez de deux interfaces d'accès aux données différentes, par exemple une IReadableStoreetIWritableStore définissant les méthodes communes attendues par votre application quel que soit le type de source de données utilisé.

Le type de source de données à utiliser ne devrait pas changer la façon dont le code client récupère ses classes d'accès aux données. Votre AbstractDataAccessFactorysait quel type de source de données est configuré et fournit une fabrique concrète pour le code client, c'est SqlDataAccessFactory-à- dire ou XmlDataAccessFactory. Ces usines concrètes peuvent créer les implémentations concrètes, par exemple SqlReadableStoreet SqlWriteableStore.

La DbProviderFactory dans .NET Framework est un exemple de ce modèle.

Johannes Rudolph
la source
18
Cette réponse pourrait décrire avec précision le modèle de méthode d'usine ou le modèle d'usine statique, mais pas le modèle de fabrique abstraite.
jaco0646
5

Si je vous comprends bien, la question est: pourquoi avons-nous à la fois la méthode Factory et les modèles d'usine abstraites. Vous avez besoin d'une fabrique abstraite lorsque différentes classes polymorphes ont une procédure d'instanciation différente. Et vous voulez qu'un module crée des instances et les utilise, sans connaître les détails de l'initialisation des objets. Par exemple, vous souhaitez créer des objets Java en effectuant des calculs. Mais certains d'entre eux font partie de l'application, tandis que le bytecode des autres doit être lu à partir de la base de données. D'autre part, pourquoi avons-nous besoin d'une méthode d'usine? D'accord, cette usine abstraite la recouvre. Mais dans certains cas, c'est beaucoup moins de code à écrire, avoir moins de classes et d'interfaces rend le système plus facile à comprendre.

David Gruzman
la source
4

Quelle est l'utilisation de Abstract Factory Pattern car nous pouvons réaliser la tâche en créant un objet de la classe concrète elle-même. Pourquoi avons-nous une méthode d'usine qui crée un objet de la classe Concrete?

En l'absence de Abstract Factory , le client a besoin de connaître les détails des classes concrètes. Ce couplage serré a été supprimé avec la fabrique abstraite .

Maintenant méthode d'usine expose un contrat que le client doit utiliser. Vous pouvez ajouter plus de produits à votre usine en ajoutant de nouveaux produits, qui implémentent l'interface exposée par la méthode d'usine.

Référez-vous à ces questions SE connexes pour une meilleure compréhension:

Quelle est la différence fondamentale entre les modèles Factory et Abstract Factory?

Intention:

Fournit une interface pour créer des familles d'objets liés ou dépendants sans spécifier leurs classes concrètes.

Vous pouvez comprendre l' intention, la structure, la liste de contrôle et les règles générales du modèle Abstract Factory à partir de cet article sur la création de sources .

Liste de contrôle:

  1. Décidez si l' indépendance de la plateforme et les services de création sont la source actuelle de douleur.
  2. Tracez une matrice de plates - formes par rapport aux produits .
  3. Définissez une interface d'usine qui consiste en une méthode d'usine par produit.
  4. Définissez une classe dérivée d' usine pour chaque plateforme qui encapsule toutes les références au nouvel opérateur.
  5. Le client doit retirer toutes les références à new et utiliser les méthodes de fabrique pour créer les objets produit .
Ravindra babu
la source
2

Les usines abstraites sont idéales pour prendre en charge plusieurs plates-formes tout en gardant votre base de code unifiée. Supposons que vous ayez un grand programme Qt ou GTK + ou .NET / Mono que vous souhaitez exécuter sous Windows, Linux et OSX. Mais vous avez une fonctionnalité qui est implémentée de manière différente sur chaque plate-forme (peut-être via l'API kernel32 ou une fonctionnalité POSIX).

public abstract class Feature
{
    public abstract int PlatformSpecificValue { get; }

    public static Feature PlatformFeature
    {
        get
        {
            string platform;
            // do platform detection here
            if (platform == "Win32")
                return new Win32Feature();
            if (platform == "POSIX")
                return new POSIXFeature();
        }
    }

    // platform overrides omitted
}

Avec cette usine abstraite, votre interface utilisateur n'a pas besoin de savoir quoi que ce soit sur la plate-forme actuelle.

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);
piedar
la source
1
Je ne comprends pas, en quoi est-ce différent de simplement utiliser des méthodes d'usine pour renvoyer un type abstrait afin que le client ne connaisse pas les détails de l'implémentation?
kiwicomb123
1

Si vous regardez les modèles de conception, presque tous peuvent être rendus superflus. Mais quel modèle signifie une approche couramment utilisée pour une solution à un type similaire de problèmes. Un modèle de conception vous offre une approche ou une solution au niveau de la conception à un ensemble de type similaire de problème de conception. L'utilisation du modèle de conception vous aide à résoudre votre problème et donc à livrer plus rapidement.

Kangkan
la source
1

c'est facile, en imaginant que vous avez un code qui fonctionne avec l'abstraction, vous devez créer des abstractions et non des classes concrètes.

Vous devez toujours travailler contre les abstractions car vous pouvez mieux modifier le code.

Voici un bon exemple: http://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23

Pablo Castilla
la source
1

Je trouve le modèle Abstract Factory surfait.

Tout d'abord, il ne se produit pas que souvent que vous avez un ensemble de interreliées types que vous souhaitez instancier.

Deuxièmement, le niveau d'indirection (abstraction) fourni par les interfaces suffit normalement lorsque l'on travaille avec l'injection de dépendances.

L'exemple typique de WindowsGui vs MacGui vs ... où vous auriez un WindowsButton, MacButton, WindowsScrollBar, MacScrollbar, etc. est souvent plus facile à implémenter en définissant des boutons concrets , des barres de défilement, etc. comportement réel.

eljenso
la source
theres un but spécifique pour cela. avec l'injection de dépendances, vous ne voulez pas de localisateurs de services plus bas depuis la racine composite. à la place, vous utilisez une fabrique abstraite injectée.
Adam Tuliper - MSFT
2
eh bien ... l'utilisation du localisateur de services avec DI est un anti-patteren. Une fabrique abstraite est la solution universelle lorsque nous devons créer des DÉPENDANCES à partir de valeurs d'exécution.
TheMentor
1

Je pense qu'il y a une place pour un motif d'usine abstrait plutôt qu'un simple motif d'usine dans les endroits où vos instanciations sont très compliquées, trop compliquées et laides pour une seule usine et trop compliquées pour que l'interface utilisateur les comprenne.

Disons que c'est une marque TYPE_A pas une seule classe ... disons qu'il existe une famille de 100 sortes de classes similaires de Type-A et que vous devez instancier un objet à partir d'elles. Imaginez qu'une information détaillée et sophistiquée soit nécessaire pour créer le bon objet à partir d'une marque de nombreux types d'objets similaires, et dans cette entité objet, vous devez savoir exactement quels paramètres régler et comment les régler.

Dans l'usine spéciale pour cette marque, nous leur demanderons de se différencier et d'obtenir l'objet exact à instancier et aussi comment l'instancier. nous saurons que selon les entrées du net (disons quelle couleur est disponible dans la boutique en ligne), et d'autres applications et services fonctionnant en arrière-plan (paramètres, l'interface utilisateur n'en a pas connaissance).

Et peut-être que demain nous aurons une autre famille de disons type_B et type_C à instancier. Ainsi, l'interface utilisateur aura le "if else" pour savoir si l'utilisateur veut un "type_A", "type_B" ou "type_C" - mais les classes des usines décideront exactement quelle classe du type (de la famille) à construire, et comment le régler - quelles valeurs régler sur ses paramètres ou envoyer à son entrepreneur. Tout cela - selon de nombreux paramètres dont l'interface utilisateur n'a pas connaissance. Tout cela sera trop pour une seule classe d'usine.

Udi Reshef
la source
1

Un exemple réel est fourni dans l'espace de noms System.Data.Common qui a des classes de base abstraites qui incluent DbConnection, DbCommand et DbDataAdapter et sont partagés par les fournisseurs de données .NET Framework, tels que System.Data.SqlClient et System.Data.OracleClient qui permettre à un développeur d'écrire un code d'accès aux données générique qui ne dépend pas d'un fournisseur de données spécifique.

La classe DbProviderFactories fournit des méthodes statiques pour créer une instance DbProviderFactory. L'instance renvoie ensuite un objet fortement typé correct basé sur les informations du fournisseur et la chaîne de connexion fournie au moment de l'exécution.

Exemple:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

entrez la description de l'image ici

        /* Getting SqlClient family members */
        DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        DbCommand dbCommand = dbProviderFactory.CreateCommand();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
        SqlConnection sqlConnection = (SqlConnection)dbConnection;
        SqlCommand sqlCommand = (SqlCommand) dbCommand;
        SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;

        /* Getting OracleClient family members*/
        dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
        dbCommand = dbProviderFactory.CreateCommand();
        dbConnection = dbProviderFactory.CreateConnection();
        dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
        OracleConnection oracleConnection = (OracleConnection)dbConnection;
        OracleCommand oracleCommand = (OracleCommand)dbCommand;
        OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;

Exemple-2 entrez la description de l'image ici

Architecture de la solution de code entrez la description de l'image ici

Les instances d'usine en béton sont fournies en utilisant la méthode d'usine statique comme ci-dessous

public  class FurnitureProviderFactory
{
    public static IFurnitureFactory GetFactory(string furnitureType)
    {
        if (furnitureType == "Wood")
        {
            return new WoodenFurnitureFactory();
        }
        if (furnitureType == "Plastic")
        {
            return new PlasticFurnitureFactory();
        }
        throw new Exception("Undefined Furniture");
    }
}
Hemendr
la source
0

Pour répondre directement à votre question, vous pouvez probablement vous en sortir sans utiliser un tel modèle de conception.

Cependant, gardez à l'esprit que la plupart des projets dans le monde réel évoluent et que vous souhaitez fournir une sorte d'extensibilité afin de rendre votre projet pérenne.

D'après ma propre expérience, la plupart du temps, une usine est implémentée et à mesure que le projet grandit, elle se transforme en modèles de conception plus complexes tels qu'une usine abstraite.

BlueTrin
la source
0

Tout est question de dépendances. Si vous ne vous souciez pas du couplage étroit et des dépendances, vous n'avez pas besoin d'une fabrique abstraite. Mais cela importera dès que vous écrivez une application qui nécessite une maintenance.

Daniel
la source
0

Supposons que vous créez un.jar et que quelqu'un d'autre utilise votre fichier jar et souhaite utiliser un nouvel objet concret dans votre code. Si vous n'utilisez pas de fabrique abstraite, elle doit modifier votre code ou écraser votre code. Mais si vous utilisez une fabrique abstraite, elle peut fournir une usine et passer à votre code et tout va bien.

Version raffinée: considérez le scénario ci-dessous : Quelqu'un d'autre a écrit un framework. Le framework utilise une fabrique abstraite et des usines concrètes pour créer de nombreux objets au moment de l'exécution. Ainsi, vous pouvez facilement enregistrer votre propre usine dans le framework existant et créer vos propres objets. Le framework est fermé aux modifications et toujours facile à étendre en raison du modèle d'usine abstrait.

Adrian Liu
la source
0

Ce modèle est particulièrement utile lorsque le client ne sait pas exactement quel type créer. À titre d'exemple, disons qu'un Showroom vendant exclusivement des téléphones portables reçoit une requête pour les téléphones intelligents fabriqués par Samsung. Ici, nous ne savons pas le type exact d'objet à créer (en supposant que toutes les informations d'un téléphone sont enveloppées sous la forme d'un objet concret). Mais nous savons que nous recherchons des téléphones intelligents fabriqués par Samsung. Ces informations peuvent en fait être utilisées si notre conception a une implémentation en usine abstraite.

Comprendre et implémenter un modèle de fabrique abstraite en C #

Amir Shabani
la source