Поиск…


замечания

Шаги создания нацелены на то, чтобы отделить систему от того, как ее объекты созданы, составлены и представлены. Они повышают гибкость системы с точки зрения того, что, кто, как и когда создает объект. Творческие шаблоны инкапсулируют знания о том, какие классы использует система, но они скрывают детали того, как создаются и объединяются экземпляры этих классов. Программисты поняли, что системы компоновки с наследованием делают эти системы слишком жесткими. Созданные шаблоны предназначены для разрыва этой тесной связи.

Шаблон Singleton

Шаблон Singleton предназначен для ограничения создания класса ровно на один экземпляр.

Этот шаблон используется в сценарии, где имеет смысл иметь только одно из следующего:

  • один класс, который организует взаимодействия других объектов, например. Класс менеджера
  • или один класс, который представляет собой уникальный, единственный ресурс, например. Компонент регистрации

Одним из наиболее распространенных способов реализации шаблона Singleton является статический заводский метод, такой как CreateInstance() или GetInstance() (или статическое свойство в C #, Instance ), который затем предназначен для возврата одного и того же экземпляра.

Первый вызов метода или свойства создает и возвращает экземпляр Singleton. После этого метод всегда возвращает один и тот же экземпляр. Таким образом, существует только один экземпляр объекта singleton.

Предотвращение создания экземпляров с помощью new может быть выполнено путем создания private. конструктора классов private.

Вот типичный пример кода для реализации шаблона Singleton в 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;
        }
    }
}

Чтобы проиллюстрировать этот шаблон далее, приведенный ниже код проверяет, возвращается ли идентичный экземпляр Singleton, когда свойство экземпляра вызывается более одного раза.

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

Примечание: эта реализация не является потокобезопасной.

Чтобы увидеть больше примеров, в том числе о том, как сделать этот поточно-безопасный, посетите: Реализация Singleton

Синглтоны концептуально похожи на глобальную ценность и вызывают подобные конструктивные недостатки и проблемы. Из-за этого шаблон Singleton широко рассматривается как анти-шаблон.

Посещение «Что так плохо в синглтонах?» для получения дополнительной информации о проблемах, возникающих при их использовании.

В C # у вас есть возможность создать класс static , который делает все члены статическими, а класс не может быть создан. Учитывая это, обычно можно увидеть статические классы, используемые вместо шаблона Singleton.

Для основных различий между ними, посетите C # Singleton Pattern Versus Static Class .

Заводская модель

Фабричный метод - один из шаблонов дизайна. Он используется для решения проблемы создания объектов без указания точного типа результата. В этом документе вы научитесь правильно использовать Factory Method DP.

Позвольте мне объяснить вам это на простом примере. Представьте, что вы работаете на заводе, производящем три типа устройств - Амперметр, вольтметр и измеритель сопротивления. Вы пишете программу для центрального компьютера, которая будет создавать выбранное устройство, но вы не знаете окончательного решения своего начальника о том, что производить.

Давайте создадим IDevice интерфейса с некоторыми общими функциями, которые есть у всех устройств:

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

Теперь мы можем создавать классы, которые представляют наши устройства. Эти классы должны реализовывать интерфейс 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..."); }
}

Теперь мы должны определить фабричный метод. Давайте создадим класс DeviceFactory со статическим методом внутри:

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

Большой! Давайте проверим наш код:

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

Это пример вывода, который вы можете увидеть после запуска этого кода:

AmMeter включается ...

36

6

33

43

24

AmMeter мигает огнями, прощаясь!

Вольтметр включается ...

102

-61

85

138

36

Вольтметр мигает огнями, прощаясь!

OhmMeter включается ...

723828

368536

685412

800266

578595

OhmMeter мигает огнями, прощаясь!

Шаблон Builder

Отделите построение сложного объекта от его представления, чтобы тот же процесс построения мог создавать различные представления и обеспечивать высокий уровень контроля над сборкой объектов.

В этом примере демонстрируется шаблон Builder, в котором различные машины собираются поэтапно. Магазин использует VehicleBuilders для создания различных транспортных средств в серии последовательных шагов.

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

Выход


Тип транспортного средства: Скутер Рамка: Скутер
Двигатель: нет
#Wheels: 2
#Doors: 0


Тип автомобиля: Автомобиль
Рамка: Автомобильная рамка
Двигатель: 2500 куб. См.
#Wheels: 4
#Doors: 4


Тип транспортного средства: Мотоцикл
Рамка: рамка мотоцикла
Двигатель: 500 куб. См
#Wheels: 2
#Doors: 0

Шаблон прототипа

Укажите тип объектов, созданных с использованием прототипа, и создайте новые объекты, скопировав этот прототип.

В этом примере демонстрируется шаблон Prototype, в котором новые объекты Color создаются путем копирования уже существующих, определяемых пользователем цветов одного и того же типа.

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

Выход:

Цвет клонирования RGB: 255, 0, 0

Цвет клонирования RGB: 128 211 128

Цвет клонирования RGB: 211, 34, 20

Абстрактный шаблон завода

Предоставить интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.

В этом примере демонстрируется создание разных животных миров для компьютерной игры с использованием разных фабрик. Хотя животные, созданные фабриками Континента, различны, взаимодействие между животными остается неизменным.

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

Выход:

Лев ест Wildebeest

Волк ест Bison



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow