Recherche…


Remarques

Les modèles de création visent à séparer un système de la façon dont ses objets sont créés, composés et représentés. Ils augmentent la flexibilité du système en termes de quoi, qui, comment et quand créer un objet. Les modèles de création encapsulent les connaissances sur les classes utilisées par un système, mais cachent les détails de la création et de la mise en forme des instances de ces classes. Les programmeurs ont compris que la composition de systèmes avec héritage rend ces systèmes trop rigides. Les motifs de création sont conçus pour briser ce couplage étroit.

Motif Singleton

Le modèle Singleton est conçu pour restreindre la création d'une classe à une seule instance.

Ce modèle est utilisé dans un scénario où il est logique de n’avoir qu’un élément comme:

  • une classe unique qui orchestre les interactions des autres objets, ex. Classe de gestionnaire
  • ou une classe qui représente une ressource unique et unique, ex. Composant d'enregistrement

L'une des méthodes les plus courantes pour implémenter le modèle Singleton consiste à CreateInstance() une méthode de fabrique statique telle que CreateInstance() ou GetInstance() (ou une propriété statique en C #, Instance ), conçue pour renvoyer toujours la même instance.

Le premier appel à la méthode ou à la propriété crée et renvoie l'instance Singleton. Par la suite, la méthode retourne toujours la même instance. De cette façon, il n'y a qu'une seule instance de l'objet singleton.

Il est possible d'empêcher la création d'instances via new en rendant le constructeur de classe private.

Voici un exemple de code typique pour l'implémentation d'un modèle Singleton en C #:

class Singleton
{
    // Because the _instance member is made private, the only way to get the single 
    // instance is via the static Instance property below. This can also be similarly 
    // achieved with a GetInstance() method instead of the property.
    private static Singleton _instance = null;

    // Making the constructor private prevents other instances from being 
    // created via something like Singleton s = new Singleton(), protecting
    // against unintentional misuse.
    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get 
        {
            // The first call will create the one and only instance.
            if (_instance == null)
            {
                _instance = new Singleton();
            }

            // Every call afterwards will return the single instance created above.
            return _instance;
        }
    }
}

Pour illustrer ce modèle, le code ci-dessous vérifie si une instance identique du Singleton est renvoyée lorsque la propriété Instance est appelée plusieurs fois.

class Program
{
    static void Main(string[] args)
    {
        Singleton s1 = Singleton.Instance;
        Singleton s2 = Singleton.Instance;
        
        // Both Singleton objects above should now reference the same Singleton instance.
        if (Object.ReferenceEquals(s1, s2))
        {
            Console.WriteLine("Singleton is working");
        }
        else
        {
            // Otherwise, the Singleton Instance property is returning something 
            // other than the unique, single instance when called.
            Console.WriteLine("Singleton is broken");
        }
    }
}

Note: cette implémentation n'est pas thread-safe.

Pour voir plus d'exemples, y compris comment rendre ce thread sûr, visitez: Mise en œuvre Singleton

Les singletons sont conceptuellement similaires à une valeur globale et provoquent des problèmes et des problèmes de conception similaires. Pour cette raison, le modèle Singleton est largement considéré comme un anti-pattern.

Visitez "Qu'est-ce qui est si mauvais à propos de Singletons?" pour plus d'informations sur les problèmes qui surviennent avec leur utilisation.

En C #, vous avez la possibilité de créer une classe static , ce qui rend tous les membres statiques et la classe ne peut pas être instanciée. Compte tenu de cela, il est courant de voir les classes statiques utilisées à la place du modèle Singleton.

Pour les différences clés entre les deux, consultez le modèle C # Singleton versus la classe statique .

Modèle de méthode d'usine

La méthode d'usine est l'un des modèles de conception créative. Il est utilisé pour résoudre le problème de la création d'objets sans spécifier le type de résultat exact. Ce document vous apprendra à utiliser correctement la méthode d'usine DP.

Laissez-moi vous en expliquer l'idée sur un exemple simple. Imaginez que vous travaillez dans une usine qui produit trois types d’appareils: un ampèremètre, un voltmètre et un compteur de résistance. Vous écrivez un programme pour un ordinateur central qui créera le périphérique sélectionné, mais vous ne connaissez pas la décision finale de votre patron sur ce qu'il doit produire.

Créons une interface IDevice avec des fonctions communes à tous les périphériques:

public interface IDevice
{
    int Measure();
    void TurnOff();
    void TurnOn();
}

Maintenant, nous pouvons créer des classes qui représentent nos appareils. Ces classes doivent implémenter l'interface IDevice :

public class AmMeter : IDevice
{
    private Random r = null;
    public AmMeter()
    {
        r = new Random();
    }
    public int Measure() { return r.Next(-25, 60); }
    public void TurnOff() { Console.WriteLine("AmMeter flashes lights saying good bye!"); }
    public void TurnOn() { Console.WriteLine("AmMeter turns on..."); }
}
public class OhmMeter : IDevice
{
    private Random r = null;
    public OhmMeter()
    {
        r = new Random();
    }
    public int Measure() { return r.Next(0, 1000000); }
    public void TurnOff() { Console.WriteLine("OhmMeter flashes lights saying good bye!"); }
    public void TurnOn() { Console.WriteLine("OhmMeter turns on..."); }
}
public class VoltMeter : IDevice
{
    private Random r = null;
    public VoltMeter()
    {
        r = new Random();
    }
    public int Measure() { return r.Next(-230, 230); }
    public void TurnOff() { Console.WriteLine("VoltMeter flashes lights saying good bye!"); }
    public void TurnOn() { Console.WriteLine("VoltMeter turns on..."); }
}

Maintenant, nous devons définir la méthode d'usine. Créons la classe DeviceFactory avec la méthode statique à l'intérieur:

public enum Device
{
    AM,
    VOLT,
    OHM
}
public class DeviceFactory
{
    public static IDevice CreateDevice(Device d)
    {
        switch(d)
        {
            case Device.AM: return new AmMeter();
            case Device.VOLT: return new VoltMeter();
            case Device.OHM: return new OhmMeter();
            default: return new AmMeter();
        }
    }
}

Génial! Testons notre code:

public class Program
{
    static void Main(string[] args)
    {
        IDevice device = DeviceFactory.CreateDevice(Device.AM);
        device.TurnOn();
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        device.TurnOff();
        Console.WriteLine();

        device = DeviceFactory.CreateDevice(Device.VOLT);
        device.TurnOn();
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        device.TurnOff();
        Console.WriteLine();

        device = DeviceFactory.CreateDevice(Device.OHM);
        device.TurnOn();
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        Console.WriteLine(device.Measure());
        device.TurnOff();
        Console.WriteLine();
    }
}

Voici l'exemple de sortie que vous pourriez voir après avoir exécuté ce code:

AmMeter allume ...

36

6

33

43

24

AmMeter clignote des lumières en disant au revoir!

VoltMeter s'allume ...

102

-61

85

138

36

VoltMeter clignote des lumières disant au revoir!

OhmMeter allume ...

723828

368536

685412

800266

578595

OhmMeter clignote des lumières disant au revoir!

Motif de constructeur

Séparez la construction d'un objet complexe de sa représentation afin que le même processus de construction puisse créer différentes représentations et offre un haut niveau de contrôle sur l'assemblage des objets.

Dans cet exemple, illustre le modèle Builder dans lequel différents véhicules sont assemblés de manière progressive. La boutique utilise VehicleBuilders pour construire une variété de véhicules dans une série d'étapes séquentielles.

using System;
using System.Collections.Generic;
 
namespace GangOfFour.Builder
{
  /// <summary>
  /// MainApp startup class for Real-World 
  /// Builder Design Pattern.
  /// </summary>
  public class MainApp
  {
    /// <summary>
    /// Entry point into console application.
    /// </summary>
    public static void Main()
    {
      VehicleBuilder builder;
 
      // Create shop with vehicle builders
      Shop shop = new Shop();
 
      // Construct and display vehicles
      builder = new ScooterBuilder();
      shop.Construct(builder);
      builder.Vehicle.Show();
 
      builder = new CarBuilder();
      shop.Construct(builder);
      builder.Vehicle.Show();
 
      builder = new MotorCycleBuilder();
      shop.Construct(builder);
      builder.Vehicle.Show();
 
      // Wait for user
      Console.ReadKey();
    }
  }
 
  /// <summary>
  /// The 'Director' class
  /// </summary>
  class Shop
  {
    // Builder uses a complex series of steps
    public void Construct(VehicleBuilder vehicleBuilder)
    {
      vehicleBuilder.BuildFrame();
      vehicleBuilder.BuildEngine();
      vehicleBuilder.BuildWheels();
      vehicleBuilder.BuildDoors();
    }
  }
 
  /// <summary>
  /// The 'Builder' abstract class
  /// </summary>
  abstract class VehicleBuilder
  {
    protected Vehicle vehicle;
 
    // Gets vehicle instance
    public Vehicle Vehicle
    {
      get { return vehicle; }
    }
 
    // Abstract build methods
    public abstract void BuildFrame();
    public abstract void BuildEngine();
    public abstract void BuildWheels();
    public abstract void BuildDoors();
  }
 
  /// <summary>
  /// The 'ConcreteBuilder1' class
  /// </summary>
  class MotorCycleBuilder : VehicleBuilder
  {
    public MotorCycleBuilder()
    {
      vehicle = new Vehicle("MotorCycle");
    }
 
    public override void BuildFrame()
    {
      vehicle["frame"] = "MotorCycle Frame";
    }
 
    public override void BuildEngine()
    {
      vehicle["engine"] = "500 cc";
    }
 
    public override void BuildWheels()
    {
      vehicle["wheels"] = "2";
    }
 
    public override void BuildDoors()
    {
      vehicle["doors"] = "0";
    }
  }
 
 
  /// <summary>
  /// The 'ConcreteBuilder2' class
  /// </summary>
  class CarBuilder : VehicleBuilder
  {
    public CarBuilder()
    {
      vehicle = new Vehicle("Car");
    }
 
    public override void BuildFrame()
    {
      vehicle["frame"] = "Car Frame";
    }
 
    public override void BuildEngine()
    {
      vehicle["engine"] = "2500 cc";
    }
 
    public override void BuildWheels()
    {
      vehicle["wheels"] = "4";
    }
 
    public override void BuildDoors()
    {
      vehicle["doors"] = "4";
    }
  }
 
  /// <summary>
  /// The 'ConcreteBuilder3' class
  /// </summary>
  class ScooterBuilder : VehicleBuilder
  {
    public ScooterBuilder()
    {
      vehicle = new Vehicle("Scooter");
    }
 
    public override void BuildFrame()
    {
      vehicle["frame"] = "Scooter Frame";
    }
 
    public override void BuildEngine()
    {
      vehicle["engine"] = "50 cc";
    }
 
    public override void BuildWheels()
    {
      vehicle["wheels"] = "2";
    }
 
    public override void BuildDoors()
    {
      vehicle["doors"] = "0";
    }
  }
 
  /// <summary>
  /// The 'Product' class
  /// </summary>
  class Vehicle
  {
    private string _vehicleType;
    private Dictionary<string,string> _parts = 
      new Dictionary<string,string>();
 
    // Constructor
    public Vehicle(string vehicleType)
    {
      this._vehicleType = vehicleType;
    }
 
    // Indexer
    public string this[string key]
    {
      get { return _parts[key]; }
      set { _parts[key] = value; }
    }
 
    public void Show()
    {
      Console.WriteLine("\n---------------------------");
      Console.WriteLine("Vehicle Type: {0}", _vehicleType);
      Console.WriteLine(" Frame : {0}", _parts["frame"]);
      Console.WriteLine(" Engine : {0}", _parts["engine"]);
      Console.WriteLine(" #Wheels: {0}", _parts["wheels"]);
      Console.WriteLine(" #Doors : {0}", _parts["doors"]);
    }
  }
}

Sortie


Type de véhicule: Cadre de scooter: Cadre de scooter
Moteur: aucun
# Roues: 2
#Portes: 0


Type de véhicule: voiture
Cadre: cadre de voiture
Moteur: 2500 cc
# Roues: 4
#Portes: 4


Type de véhicule: MotorCycle
Cadre: Cadre MotorCycle
Moteur: 500 cc
# Roues: 2
#Portes: 0

Motif Prototype

Spécifiez le type d'objets à créer à l'aide d'une instance de prototype et créez de nouveaux objets en copiant ce prototype.

Dans cet exemple, illustre le modèle Prototype dans lequel les nouveaux objets Couleur sont créés en copiant les couleurs préexistantes définies par l'utilisateur du même type.

using System;
using System.Collections.Generic;
 
namespace GangOfFour.Prototype
{
  /// <summary>
  /// MainApp startup class for Real-World 
  /// Prototype Design Pattern.
  /// </summary>
  class MainApp
  {
    /// <summary>
    /// Entry point into console application.
    /// </summary>
    static void Main()
    {
      ColorManager colormanager = new ColorManager();
 
      // Initialize with standard colors
      colormanager["red"] = new Color(255, 0, 0);
      colormanager["green"] = new Color(0, 255, 0);
      colormanager["blue"] = new Color(0, 0, 255);
 
      // User adds personalized colors
      colormanager["angry"] = new Color(255, 54, 0);
      colormanager["peace"] = new Color(128, 211, 128);
      colormanager["flame"] = new Color(211, 34, 20);
 
      // User clones selected colors
      Color color1 = colormanager["red"].Clone() as Color;
      Color color2 = colormanager["peace"].Clone() as Color;
      Color color3 = colormanager["flame"].Clone() as Color;
 
      // Wait for user
      Console.ReadKey();
    }
  }
 
  /// <summary>
  /// The 'Prototype' abstract class
  /// </summary>
  abstract class ColorPrototype
  {
    public abstract ColorPrototype Clone();
  }
 
  /// <summary>
  /// The 'ConcretePrototype' class
  /// </summary>
  class Color : ColorPrototype
  {
    private int _red;
    private int _green;
    private int _blue;
 
    // Constructor
    public Color(int red, int green, int blue)
    {
      this._red = red;
      this._green = green;
      this._blue = blue;
    }
 
    // Create a shallow copy
    public override ColorPrototype Clone()
    {
      Console.WriteLine(
        "Cloning color RGB: {0,3},{1,3},{2,3}",
        _red, _green, _blue);
 
      return this.MemberwiseClone() as ColorPrototype;
    }
  }
 
  /// <summary>
  /// Prototype manager
  /// </summary>
  class ColorManager
  {
    private Dictionary<string, ColorPrototype> _colors =
      new Dictionary<string, ColorPrototype>();
 
    // Indexer
    public ColorPrototype this[string key]
    {
      get { return _colors[key]; }
      set { _colors.Add(key, value); }
    }
  }
}

Sortie:

Couleur de clonage RVB: 255, 0, 0

Couleur de clonage RVB: 128,211,128

Couleur de clonage RVB: 211, 34, 20

Motif d'usine abstraite

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

Dans cet exemple montre la création de différents mondes animaux pour un jeu informatique utilisant différentes usines. Bien que les animaux créés par les usines du continent soient différents, les interactions entre les animaux restent les mêmes.

using System;
 
namespace GangOfFour.AbstractFactory
{
  /// <summary>
  /// MainApp startup class for Real-World
  /// Abstract Factory Design Pattern.
  /// </summary>
  class MainApp
  {
    /// <summary>
    /// Entry point into console application.
    /// </summary>
    public static void Main()
    {
      // Create and run the African animal world
      ContinentFactory africa = new AfricaFactory();
      AnimalWorld world = new AnimalWorld(africa);
      world.RunFoodChain();
 
      // Create and run the American animal world
      ContinentFactory america = new AmericaFactory();
      world = new AnimalWorld(america);
      world.RunFoodChain();
 
      // Wait for user input
      Console.ReadKey();
    }
  }
 
 
  /// <summary>
  /// The 'AbstractFactory' abstract class
  /// </summary>
  abstract class ContinentFactory
  {
    public abstract Herbivore CreateHerbivore();
    public abstract Carnivore CreateCarnivore();
  }
 
  /// <summary>
  /// The 'ConcreteFactory1' class
  /// </summary>
  class AfricaFactory : ContinentFactory
  {
    public override Herbivore CreateHerbivore()
    {
      return new Wildebeest();
    }
    public override Carnivore CreateCarnivore()
    {
      return new Lion();
    }
  }
 
  /// <summary>
  /// The 'ConcreteFactory2' class
  /// </summary>
  class AmericaFactory : ContinentFactory
  {
    public override Herbivore CreateHerbivore()
    {
      return new Bison();
    }
    public override Carnivore CreateCarnivore()
    {
      return new Wolf();
    }
  }
 
  /// <summary>
  /// The 'AbstractProductA' abstract class
  /// </summary>
  abstract class Herbivore
  {
  }
 
  /// <summary>
  /// The 'AbstractProductB' abstract class
  /// </summary>
  abstract class Carnivore
  {
    public abstract void Eat(Herbivore h);
  }
 
  /// <summary>
  /// The 'ProductA1' class
  /// </summary>
  class Wildebeest : Herbivore
  {
  }
 
  /// <summary>
  /// The 'ProductB1' class
  /// </summary>
  class Lion : Carnivore
  {
    public override void Eat(Herbivore h)
    {
      // Eat Wildebeest
      Console.WriteLine(this.GetType().Name +
        " eats " + h.GetType().Name);
    }
  }
 
  /// <summary>
  /// The 'ProductA2' class
  /// </summary>
  class Bison : Herbivore
  {
  }
 
  /// <summary>
  /// The 'ProductB2' class
  /// </summary>
  class Wolf : Carnivore
  {
    public override void Eat(Herbivore h)
    {
      // Eat Bison
      Console.WriteLine(this.GetType().Name +
        " eats " + h.GetType().Name);
    }
  }
 
  /// <summary>
  /// The 'Client' class 
  /// </summary>
  class AnimalWorld
  {
    private Herbivore _herbivore;
    private Carnivore _carnivore;
 
    // Constructor
    public AnimalWorld(ContinentFactory factory)
    {
      _carnivore = factory.CreateCarnivore();
      _herbivore = factory.CreateHerbivore();
    }
 
    public void RunFoodChain()
    {
      _carnivore.Eat(_herbivore);
    }
  }
}

Sortie:

Lion mange des gnous

Le loup mange le bison



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow