Singleton Pattern (Одиночка): Один класс который имеет экземпляр предоставляющий глобальный доступ.
Factory Pattern (Фабрика): Определяет общий интерфейс для создания объектов, но не дает подклассам решать какой экземпляр класса создавать.
Observer Pattern (Наблюдатель): Определяет зависимость один ко многим между объектами, когда один объект изменяет состояние, все зависимые уведомляются автоматически.
Decorator Pattern (Декоратор): Позволяет добавлять динамически новое поведение к отдельным объектам, не затрагивая поведение других объектов того же класса.
Strategy Pattern (Стратегия): Определяет алгоритмы, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет алгоритму изменяться независимо от клиентов, которые его используют.
Adapter Pattern (Адаптер): Преобразует интерфейс класса в другой интерфейс, ожидаемый клиентами. Он позволяет классам работать вместе, что иначе невозможно из-за несовместимых интерфейсов.
Command Pattern: Инкапсулирует запрос как объект, тем самым параметризуя клиентов очередями, запросами и операциями.
Singleton Pattern (Одиночка)
using System;
public class Singleton
{
private static Singleton instance;
private Singleton() { }
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
public void DisplayMessage()
{
Console.WriteLine("This is a Singleton instance.");
}
}
class Program
{
static void Main()
{
// Attempt to create multiple instances of the Singleton class
Singleton singleton1 = Singleton.Instance;
Singleton singleton2 = Singleton.Instance;
// Both instances should be the same
Console.WriteLine("Are both instances the same? " + (singleton1 == singleton2));
// Using the singleton instance
singleton1.DisplayMessage();
}
}
В методе Main мы демонстрируем создание двух экземпляров класса Singleton и показываем, что они являются одним и тем же объектом, проверяя их ссылки. Наконец, мы вызываем метод DisplayMessage для экземпляра Singleton, чтобы показать, что это действительно единственный экземпляр.
Factory Pattern
using System;
// Product interface
interface IProduct
{
void Show();
}
// Concrete product classes
class ConcreteProduct1 : IProduct
{
public void Show()
{
Console.WriteLine("Concrete Product 1");
}
}
class ConcreteProduct2 : IProduct
{
public void Show()
{
Console.WriteLine("Concrete Product 2");
}
}
// Factory class
class ProductFactory
{
public static IProduct CreateProduct(string productType)
{
switch (productType)
{
case "1":
return new ConcreteProduct1();
case "2":
return new ConcreteProduct2();
default:
throw new ArgumentException("Invalid product type");
}
}
}
class Program
{
static void Main()
{
// Using the factory to create objects
IProduct product1 = ProductFactory.CreateProduct("1");
product1.Show();
IProduct product2 = ProductFactory.CreateProduct("2");
product2.Show();
}
}
В методе Main мы используем фабрику для создания экземпляров ConcreteProduct1 и ConcreteProduct2 без их непосредственного создания экземпляров. Таким образом, фабрика инкапсулирует логику создания объектов и предоставляет централизованное место для создания объектов на основе определенных условий или параметров.
Observer Pattern
using System;
using System.Collections.Generic;
// Subject interface
interface ISubject
{
void RegisterObserver(IObserver observer);
void RemoveObserver(IObserver observer);
void NotifyObservers();
}
// Observer interface
interface IObserver
{
void Update(string message);
}
// Concrete subject class
class Subject : ISubject
{
private List<IObserver> observers = new List<IObserver>();
private string message;
public void RegisterObserver(IObserver observer)
{
observers.Add(observer);
}
public void RemoveObserver(IObserver observer)
{
observers.Remove(observer);
}
public void NotifyObservers()
{
foreach (var observer in observers)
{
observer.Update(message);
}
}
public void SetMessage(string message)
{
this.message = message;
NotifyObservers();
}
}
// Concrete observer class
class ConcreteObserver : IObserver
{
private string name;
public ConcreteObserver(string name)
{
this.name = name;
}
public void Update(string message)
{
Console.WriteLine($"{name} received message: {message}");
}
}
class Program
{
static void Main()
{
Subject subject = new Subject();
ConcreteObserver observer1 = new ConcreteObserver("Observer 1");
ConcreteObserver observer2 = new ConcreteObserver("Observer 2");
subject.RegisterObserver(observer1);
subject.RegisterObserver(observer2);
subject.SetMessage("Hello, Observers!");
}
}
В методе Main мы создаем экземпляр subject и два экземпляра ConcreteObserver. Регистрируем обоих наблюдателей с субъектом, а затем устанавливаем сообщение на субъекте. Это заставляет субъект уведомлять всех зарегистрированных наблюдателей об изменении сообщения, и каждый наблюдатель распечатывает полученное сообщение.
Decorator Pattern
using System;
// Component interface
public interface ICar
{
string GetDescription();
double GetCost();
}
// Concrete component
public class EconomyCar : ICar
{
public string GetDescription()
{
return "Economy Car";
}
public double GetCost()
{
return 20000.0;
}
}
// Decorator
public abstract class CarDecorator : ICar
{
protected ICar _car;
public CarDecorator(ICar car)
{
_car = car;
}
public virtual string GetDescription()
{
return _car.GetDescription();
}
public virtual double GetCost()
{
return _car.GetCost();
}
}
// Concrete decorator
public class SportsPackage : CarDecorator
{
public SportsPackage(ICar car) : base(car)
{
}
public override string GetDescription()
{
return $"{base.GetDescription()}, Sports Package";
}
public override double GetCost()
{
return base.GetCost() + 5000.0;
}
}
class Program
{
static void Main()
{
// Create an economy car
ICar economyCar = new EconomyCar();
Console.WriteLine($"Description: {economyCar.GetDescription()}, Cost: {economyCar.GetCost()}");
// Add sports package to the economy car using decorator
ICar sportsCar = new SportsPackage(economyCar);
Console.WriteLine($"Description: {sportsCar.GetDescription()}, Cost: {sportsCar.GetCost()}");
}
}
В методе Main мы создаем экземпляр автомобиля эконом-класса, затем украшаем его спортивной комплектацией с помощью шаблона декоратора.
Strategy Pattern
using System;
// Strategy interface
public interface IStrategy
{
void Execute();
}
// Concrete strategies
public class ConcreteStrategyA : IStrategy
{
public void Execute()
{
Console.WriteLine("Executing strategy A");
}
}
public class ConcreteStrategyB : IStrategy
{
public void Execute()
{
Console.WriteLine("Executing strategy B");
}
}
// Context class
public class Context
{
private IStrategy _strategy;
public Context(IStrategy strategy)
{
_strategy = strategy;
}
public void SetStrategy(IStrategy strategy)
{
_strategy = strategy;
}
public void ExecuteStrategy()
{
_strategy.Execute();
}
}
class Program
{
static void Main()
{
// Create context with a default strategy
Context context = new Context(new ConcreteStrategyA());
// Execute the default strategy
context.ExecuteStrategy();
// Change the strategy at runtime
context.SetStrategy(new ConcreteStrategyB());
// Execute the new strategy
context.ExecuteStrategy();
}
}
В методе Main мы создаем объект Context со стратегией по умолчанию ConcreteStrategyA, выполняем эту стратегию по умолчанию, затем во время выполнения меняем стратегию на ConcreteStrategyB и выполняем ее. Это демонстрирует, как шаблон стратегии позволяет изменять поведение объекта во время выполнения, изменяя его стратегию.
Adapter pattern
using System;
// Target interface that the client code expects to work with
interface ITarget
{
void Request();
}
// Adaptee class that needs to be adapted to work with the client code
class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("Adaptee's specific request.");
}
}
// Adapter class that adapts the Adaptee to the Target interface
class Adapter : ITarget
{
private readonly Adaptee adaptee;
public Adapter(Adaptee adaptee)
{
this.adaptee = adaptee;
}
public void Request()
{
adaptee.SpecificRequest();
}
}
class Program
{
static void Main()
{
// Using the Adaptee class directly
Adaptee adaptee = new Adaptee();
adaptee.SpecificRequest();
// Using the Adapter to adapt the Adaptee to the ITarget interface
ITarget adapter = new Adapter(adaptee);
adapter.Request();
}
}
- ITarget — это целевой интерфейс, с которым ожидается работа клиентского кода.
- Adaptee — это класс, имеющий другой интерфейс, который необходимо адаптировать.
- Adapter — это класс адаптера, который реализует интерфейс ITarget и делегирует запрос Adaptee.
- В методе Main мы демонстрируем непосредственное использование класса Adaptee, а затем его адаптацию с помощью класса Adapter для работы с интерфейсом ITarget.
Этот шаблон позволяет объектам с несовместимыми интерфейсами работать вместе. Адаптер действует как мост между клиентским кодом и Адаптируемым, позволяя им беспрепятственно работать вместе.
Command Pattern
using System;
using System.Collections.Generic;
// Command interface
interface ICommand
{
void Execute();
}
// Receiver class
class Receiver
{
public void Action()
{
Console.WriteLine("Receiver is performing an action.");
}
}
// Concrete command classes
class ConcreteCommand1 : ICommand
{
private Receiver receiver;
public ConcreteCommand1(Receiver receiver)
{
this.receiver = receiver;
}
public void Execute()
{
receiver.Action();
Console.WriteLine("ConcreteCommand1 executed.");
}
}
class ConcreteCommand2 : ICommand
{
private Receiver receiver;
public ConcreteCommand2(Receiver receiver)
{
this.receiver = receiver;
}
public void Execute()
{
receiver.Action();
Console.WriteLine("ConcreteCommand2 executed.");
}
}
// Invoker class
class Invoker
{
private List<ICommand> commands = new List<ICommand>();
public void AddCommand(ICommand command)
{
commands.Add(command);
}
public void ExecuteCommands()
{
foreach (var command in commands)
{
command.Execute();
}
}
}
class Program
{
static void Main()
{
Receiver receiver = new Receiver();
ICommand command1 = new ConcreteCommand1(receiver);
ICommand command2 = new ConcreteCommand2(receiver);
Invoker invoker = new Invoker();
invoker.AddCommand(command1);
invoker.AddCommand(command2);
invoker.ExecuteCommands();
}
}
- ICommand — это командный интерфейс, в котором объявляется метод выполнения команды.
- Receiver — это класс, который выполняет фактическое действие, связанное с командой.
- ConcreteCommand1 и ConcreteCommand2 — это конкретные классы команд, которые реализуют интерфейс ICommand и выполняют определенные действия на приемнике.
- Invoker — это класс, который содержит и выполняет список команд.
- В методе Main мы создаём экземпляры приёмника, конкретных команд и инициатора. Мы добавляем команды в вызывающую программу и затем выполняем их.
Этот шаблон отделяет отправителя запроса от объекта, который выполняет запрос, обеспечивая гибкость в параметризации клиентов с различными запросами, а также в организации очереди или регистрации запросов.