Buscar..


Observaciones

Los patrones creacionales apuntan a separar un sistema de cómo se crean, se componen y se representan sus objetos. Aumentan la flexibilidad del sistema en términos de qué, quién, cómo y cuándo de creación de objetos. Los patrones de creación encapsulan el conocimiento sobre qué clases usa un sistema, pero ocultan los detalles de cómo se crean y se juntan las instancias de estas clases. Los programadores se han dado cuenta de que componer sistemas con herencia hace que esos sistemas sean demasiado rígidos. Los patrones de creación están diseñados para romper este acoplamiento cercano.

Patrón Singleton

El patrón Singleton está diseñado para restringir la creación de una clase a una sola instancia.

Este patrón se usa en un escenario donde tiene sentido tener solo uno de algo, como por ejemplo:

  • una sola clase que organiza las interacciones de otros objetos, ej. Clase de gerente
  • o una clase que representa un recurso único y único, ej. Componente de registro

Una de las formas más comunes de implementar el patrón Singleton es a través de un método de fábrica estático como CreateInstance() o GetInstance() (o una propiedad estática en C #, Instance ), que luego está diseñada para devolver siempre la misma instancia.

La primera llamada al método o propiedad crea y devuelve la instancia de Singleton. A partir de entonces, el método siempre devuelve la misma instancia. De esta manera, solo hay una instancia del objeto singleton.

La prevención de la creación de instancias a través de new puede lograrse haciendo que los constructores de la clase sean private.

Este es un ejemplo típico de código para implementar un patrón 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;
        }
    }
}

Para ilustrar aún más este patrón, el siguiente código comprueba si se devuelve una instancia idéntica de Singleton cuando se llama a la propiedad Instancia más de una vez.

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");
        }
    }
}

Nota: esta implementación no es segura para subprocesos.

Para ver más ejemplos, incluyendo cómo hacer que este hilo sea seguro, visite: Implementación de Singleton

Los Singletons son conceptualmente similares a un valor global y causan fallas e inquietudes de diseño similares. Debido a esto, el patrón Singleton es ampliamente considerado como un anti-patrón.

Visita "¿Qué tiene de malo Singletons?" Para más información sobre los problemas que surgen con su uso.

En C #, tiene la capacidad de hacer que una clase sea static , lo que hace que todos los miembros sean estáticos, y la clase no puede ser instanciada. Dado esto, es común ver las clases estáticas utilizadas en lugar del patrón Singleton.

Para conocer las diferencias clave entre los dos, visite C # Singleton Pattern Versus Static Class .

Patrón de método de fábrica

Método de fábrica es uno de los patrones de diseño creativo. Se utiliza para tratar el problema de crear objetos sin especificar el tipo de resultado exacto. Este documento le enseñará cómo utilizar Factory Method DP correctamente.

Déjame explicarte la idea de ello en un ejemplo simple. Imagine que está trabajando en una fábrica que produce tres tipos de dispositivos: amperímetro, voltímetro y medidor de resistencia. Está escribiendo un programa para una computadora central que creará el dispositivo seleccionado, pero no sabe la decisión final de su jefe sobre qué producir.

IDevice un IDevice interfaz con algunas funciones comunes que todos los dispositivos tienen:

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

Ahora, podemos crear clases que representen nuestros dispositivos. Esas clases deben implementar la interfaz 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..."); }
}

Ahora tenemos que definir el método de fábrica. Vamos a crear la clase DeviceFactory con el método estático dentro de:

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();
        }
    }
}

¡Genial! Probemos nuestro código:

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();
    }
}

Este es el ejemplo de salida que puede ver después de ejecutar este código:

AmMeter enciende ...

36

6

33

43

24

AmMeter parpadea luces diciendo adiós!

VoltMeter enciende ...

102

-61

85

138

36

VoltMeter parpadea luces diciendo adiós!

OhmMeter enciende ...

723828

368536

685412

800266

578595

OhmMeter parpadea luces diciendo adiós!

Patrón de constructor

Separe la construcción de un objeto complejo de su representación para que el mismo proceso de construcción pueda crear diferentes representaciones y proporcione un alto nivel de control sobre el ensamblaje de los objetos.

En este ejemplo, se muestra el patrón de Generador en el que los diferentes vehículos se ensamblan paso a paso. La tienda utiliza VehicleBuilders para construir una variedad de vehículos en una serie de pasos secuenciales.

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"]);
    }
  }
}

Salida


Tipo de vehículo: Marco de scooter: Marco de scooter
Motor: ninguno
# Ruedas: 2
#Puertas: 0


Tipo de vehículo: Coche
Marco: Marco del coche
Motor: 2500 cc
# Ruedas: 4
#Puertas: 4


Tipo de vehículo: MotorCycle
Cuadro: Cuadro MotorCycle
Motor: 500 cc
# Ruedas: 2
#Puertas: 0

Patrón prototipo

Especifique el tipo de objetos para crear utilizando una instancia prototípica y cree nuevos objetos copiando este prototipo.

En este ejemplo, se muestra el patrón de prototipo en el que se crean nuevos objetos de color al copiar colores preexistentes definidos por el usuario del mismo tipo.

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); }
    }
  }
}

Salida:

Color de clonación RGB: 255, 0, 0

Color de clonación RGB: 128,211,128

Color de clonación RGB: 211, 34, 20

Patrón abstracto de la fábrica

Proporcionar una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.

En este ejemplo, se demuestra la creación de diferentes mundos animales para un juego de computadora que utiliza diferentes fábricas. Aunque los animales creados por las fábricas del Continente son diferentes, las interacciones entre los animales siguen siendo las mismas.

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);
    }
  }
}

Salida:

León come ñu

Lobo come bisonte



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow