Введение в творческие шаблоны

Creational Patterns — это шаблоны проектирования, ориентированные на механизмы создания объектов, помогающие разработчикам создавать объекты гибким, удобным и эффективным способом. Эти шаблоны обеспечивают решения общих проблем, связанных с созданием объектов, делая процесс проектирования программного обеспечения более рациональным и эффективным.

В этом сообщении блога мы рассмотрим пять основных шаблонов создания с примерами кода на C#:

  • Одиночка
  • Заводской метод
  • Абстрактная фабрика
  • Конструктор
  • Прототип

1. Одноэлементный шаблон

Шаблон Singleton гарантирует, что класс имеет только один экземпляр, и обеспечивает глобальную точку доступа к этому экземпляру. Это особенно полезно, когда одного экземпляра класса достаточно для координации действий в системе.

1.1. Реализация шаблона Singleton в .NET

** УЛУЧШЕНО `замком` **

// ! Ensures that a class has only one instance and provides a global point of access to that instance
    public sealed class Singleton
    {
        private static Singleton? instance = null;
        private static readonly object padlock = new object();

        private Singleton()
        {
            // construct logic 
        }

        public static Singleton Instance
        {
            get
            {
                lock (padlock) // to prevent multiple threads from accessing the instance simultaneously
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                    return instance;
                }
            }
        }
    }

Использование:

class Program
{
    static void Main(string[] args)
    {
        Singleton instance1 = Singleton.Instance;
        Singleton instance2 = Singleton.Instance;

        if (instance1 == instance2)
        {
            Console.WriteLine("Both instances are the same.");
        }
        else
        {
            Console.WriteLine("Instances are different.");
        }
    }
}

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

Когда вы запустите пример, вы увидите, что instance1 и instance2 совпадают, что указывает на то, что существует только один экземпляр класса Singleton.

2. Шаблон фабричного метода

Шаблон Factory Method определяет интерфейс для создания объекта, но позволяет подклассам решать, экземпляр какого класса создавать. Он предоставляет способ делегировать процесс создания экземпляров дочерним классам.

2.1. Реализация шаблона фабричного метода в .NET

public abstract class Animal
{
    public abstract string Speak();
}

public class Dog : Animal
{
    public override string Speak()
    {
        return "Woof!";
    }
}

public class Cat : Animal
{
    public override string Speak()
    {
        return "Meow!";
    }
}

public abstract class AnimalFactory
{
    public abstract Animal CreateAnimal();
}

public class DogFactory : AnimalFactory
{
    public override Animal CreateAnimal()
    {
        return new Dog();
    }
}

public class CatFactory : AnimalFactory
{
    public override Animal CreateAnimal()
    {
        return new Cat();
    }
}

Использование:

class Program
{
    static void Main(string[] args)
    {
        AnimalFactory dogFactory = new DogFactory();
        Animal dog = dogFactory.CreateAnimal();
        Console.WriteLine(dog.Speak());

        AnimalFactory catFactory = new CatFactory();
        Animal cat = catFactory.CreateAnimal();
        Console.WriteLine(cat.Speak());
    }
}

В приведенном выше примере класс Animal служит базовым классом для Dog и Cat. Класс AnimalFactory является абстрактным базовым классом для классов DogFactory и CatFactory, которые отвечают за создание экземпляров Dog и Cat соответственно. Шаблон Factory Method обеспечивает гибкость в создании объектов, поскольку новые типы животных могут быть добавлены без изменения существующего кода.

Когда вы запустите пример, вы увидите выходные данные метода Speak для каждого типа животных, демонстрирующие, что шаблон фабричного метода успешно создал экземпляры классов Dog и Cat.

3. Абстрактная фабрика

Шаблон Abstract Factory предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов. Это позволяет вам создавать объекты, принадлежащие определенному семейству, без необходимости знать их конкретные классы.

3.1. Реализация шаблона абстрактной фабрики в .NET

// Abstract products
public interface IButton
{
    void Click();
}

public interface ITextBox
{
    void Type(string text);
}

// Concrete products
public class WindowsButton : IButton
{
    public void Click()
    {
        Console.WriteLine("WindowsButton clicked.");
    }
}

public class WindowsTextBox : ITextBox
{
    public void Type(string text)
    {
        Console.WriteLine($"WindowsTextBox text: {text}");
    }
}

public class LinuxButton : IButton
{
    public void Click()
    {
        Console.WriteLine("LinuxButton clicked.");
    }
}

public class LinuxTextBox : ITextBox
{
    public void Type(string text)
    {
        Console.WriteLine($"LinuxTextBox text: {text}");
    }
}

// Abstract Factory
public interface IGUIFactory
{
    IButton CreateButton();
    ITextBox CreateTextBox();
}

// Concrete Factories
public class WindowsGUIFactory : IGUIFactory
{
    public IButton CreateButton()
    {
        return new WindowsButton();
    }

    public ITextBox CreateTextBox()
    {
        return new WindowsTextBox;
    }
}

public class LinuxGUIFactory : IGUIFactory
{
    public IButton CreateButton()
    {
        return new LinuxButton();
    }

    public ITextBox CreateTextBox()
    {
        return new LinuxTextBox();
    }
}

Использование:

class Program
{
    static void Main(string[] args)
    {
        IGUIFactory guiFactory;

        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            guiFactory = new WindowsGUIFactory();
        }
        else
        {
            guiFactory = new LinuxGUIFactory();
        }

        IButton button = guiFactory.CreateButton();
        button.Click();

        ITextBox textBox = guiFactory.CreateTextBox();
        textBox.Type("Hello, Abstract Factory!");
    }
}

В приведенном выше примере шаблон Abstract Factory используется для создания элементов GUI для конкретной платформы. IGUIFactory — это интерфейс для создания компонентов графического интерфейса, а WindowsGUIFactory и LinuxGUIFactory — конкретные фабрики для создания элементов графического интерфейса для конкретной платформы. Когда вы запускаете пример, создаются и используются соответствующие элементы графического интерфейса для конкретной платформы, в зависимости от операционной системы, в которой работает программа.

Используя шаблон Abstract Factory, вы можете легко добавить поддержку новых платформ или модифицировать существующие платформы без изменения клиентского кода.

4. Шаблон строителя

Шаблон Builder отделяет построение сложного объекта от его представления. Это позволяет одному и тому же процессу построения создавать различные представления. Этот шаблон особенно полезен при создании объектов с большим количеством свойств или когда процесс создания объекта включает несколько шагов.

4.1. Реализация шаблона Builder в .NET

public class Computer
{
    public string Processor { get; set; }
    public int RAM { get; set; }
    public int Storage { get; set; }

    public override string ToString()
    {
        return $"Processor: {Processor}, RAM: {RAM}GB, Storage: {Storage}GB";
    }
}

public interface IComputerBuilder
{
    void SetProcessor();
    void SetRAM();
    void SetStorage();
    Computer GetComputer();
}

public class GamingComputerBuilder : IComputerBuilder
{
    private Computer _computer;

    public GamingComputerBuilder()
    {
        _computer = new Computer();
    }

    public void SetProcessor()
    {
        _computer.Processor = "Intel Core i9";
    }

    public void SetRAM()
    {
        _computer.RAM = 32;
    }

    public void SetStorage()
    {
        _computer.Storage = 1024;
    }

    public Computer GetComputer()
    {
        return _computer;
    }
}

public class OfficeComputerBuilder : IComputerBuilder
{
    private Computer _computer;

    public OfficeComputerBuilder()
    {
        _computer = new Computer();
    }
    
    public void SetProcessor()
    {
        _computer.Processor = "Intel Core i5";
    }
    
    public void SetRAM()
    {
        _computer.RAM = 16;
    }
    
    public void SetStorage()
    {
        _computer.Storage = 512;
    }
    
    public Computer GetComputer()
    {
        return _computer;
    }
}

public class ComputerDirector
{
    public void BuildComputer(IComputerBuilder builder)
    {
        builder.SetProcessor();
        builder.SetRAM();
        builder.SetStorage();
    }
}

Использование:

class Program
{
    static void Main(string[] args)
    {
        ComputerDirector director = new ComputerDirector();

        IComputerBuilder gamingBuilder = new GamingComputerBuilder();
        director.BuildComputer(gamingBuilder);
        Computer gamingComputer = gamingBuilder.GetComputer();
        Console.WriteLine("Gaming Computer: " + gamingComputer.ToString());

        IComputerBuilder officeBuilder = new OfficeComputerBuilder();
        director.BuildComputer(officeBuilder);
        Computer officeComputer = officeBuilder.GetComputer();
        Console.WriteLine("Office Computer: " + officeComputer.ToString());
    }
}

В приведенном выше примере класс Computer представляет сложный объект, который мы хотим создать. Класс IComputerBuilderinterface defines the steps needed to build aComputerobject. TheGamingComputerBuilderandOfficeComputerBuilderclasses are concrete builders that implement theIComputerBuilderinterface, creating gaming and office computers, respectively. TheComputerDirector управляет процессом сборки, вызывая соответствующие шаги для сборки компьютера.

Когда вы запустите пример, вы увидите детали созданных игровых и офисных компьютеров, демонстрируя, что шаблон Builder успешно отделил конструкцию объектов Computer от их представления.

5. Образец прототипа

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

5.1. Реализация шаблона прототипа в .NET

public abstract class Animal : ICloneable
{
    public string Name { get; set; }
    public int Age { get; set; }

    public abstract void Speak();

    public object Clone()
    {
        return MemberwiseClone();
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

public class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Meow!");
    }
}

Использование:

class Program
{
    static void Main(string[] args)
    {
        Dog originalDog = new Dog { Name = "Max", Age = 3 };
        Dog clonedDog = (Dog)originalDog.Clone();
        clonedDog.Name = "Buddy";
        originalDog.Speak();
        clonedDog.Speak();

        Cat originalCat = new Cat { Name = "Molly", Age = 2 };
        Cat clonedCat = (Cat)originalCat.Clone();
        clonedCat.Name = "Luna";
        originalCat.Speak();
        clonedCat.Speak();
    }
}

В приведенном выше примере класс `Animal` реализует интерфейс `ICloneable` и предоставляет метод `Clone()`, использующий метод `MemberwiseClone()`, который создает поверхностную копию объекта. Классы Dog и Cat наследуются от класса Animal и переопределяют метод Speak().

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

Продолжение следует…



Повышение уровня кодирования

Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:

  • 👏 Хлопайте за историю и подписывайтесь на автора 👉
  • 📰 Смотрите больше контента в публикации Level Up Coding
  • 💰 Бесплатный курс собеседования по программированию ⇒ Просмотреть курс
  • 🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"

🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу