Sobes.tech
Junior
105
questionbank

Какие существуют паттерны проектирования в программировании?

Answer from AI

sobes.tech AI

Паттерны проектирования делятся на три основные категории: порождающие, структурные и поведенческие.

Порождающие паттерны:

  • Фабричный метод (Factory Method): Предоставляет интерфейс для создания объектов в суперклассе, но позволяет подклассам изменять тип создаваемых объектов.
    // Интерфейс продукта
    public interface IProduct
    {
        void DoSomething();
    }
    
    // Конкретный продукт A
    public class ConcreteProductA : IProduct
    {
        public void DoSomething()
        {
            // Реализация
        }
    }
    
    // Конкретный продукт B
    public class ConcreteProductB : IProduct
    {
        public void DoSomething()
        {
            // Реализация
        }
    }
    
    // Абстрактный создатель
    public abstract class Creator
    {
        // Фабричный метод
        public abstract IProduct CreateProduct();
    
        public void AnOperation()
        {
            var product = CreateProduct();
            product.DoSomething();
        }
    }
    
    // Конкретный создатель A
    public class ConcreteCreatorA : Creator
    {
        public override IProduct CreateProduct()
        {
            return new ConcreteProductA();
        }
    }
    
    // Конкретный создатель B
    public class ConcreteCreatorB : Creator
    {
        public override IProduct CreateProduct()
        {
            return new ConcreteProductB();
        }
    }
    
  • Абстрактная фабрика (Abstract Factory): Предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.
  • Строитель (Builder): Отделяет конструирование сложного объекта от его представления, так что один и тот же процесс конструирования может создавать различные представления.
    // Продукт
    public class Car
    {
        public string Engine { get; set; }
        public string Wheels { get; set; }
        public string Body { get; set; }
    
        public void Display()
        {
            // Показать детали машины
        }
    }
    
    // Интерфейс строителя
    public interface ICarBuilder
    {
        void BuildEngine();
        void BuildWheels();
        void BuildBody();
        Car GetCar();
    }
    
    // Конкретный строитель
    public class SportsCarBuilder : ICarBuilder
    {
        private Car car = new Car();
    
        public void BuildEngine()
        {
            car.Engine = "Sports Engine";
        }
    
        public void BuildWheels()
        {
            car.Wheels = "Sports Wheels";
        }
    
        public void BuildBody()
        {
            car.Body = "Sports Body";
        }
    
        public Car GetCar()
        {
            return car;
        }
    }
    
    // Директор
    public class CarDirector
    {
        public void Construct(ICarBuilder builder)
        {
            builder.BuildEngine();
            builder.BuildWheels();
            builder.BuildBody();
        }
    }
    
  • Прототип (Prototype): Задает виды создаваемых объектов с помощью экземпляра-прототипа и создает новые объекты путем копирования этого прототипа.
  • Одиночка (Singleton): Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.

Структурные паттерны:

  • Адаптер (Adapter): Преобразует интерфейс одного класса в другой интерфейс, который ожидают клиенты. Адаптер позволяет классам с несовместимыми интерфейсами работать вместе.
    // Несовместимый класс (адаптируемый)
    public class Adaptee
    {
        public void SpecificRequest()
        {
            // Реализация специфического запроса
        }
    }
    
    // Целевой интерфейс
    public interface ITarget
    {
        void Request();
    }
    
    // Адаптер
    public class Adapter : ITarget
    {
        private readonly Adaptee _adaptee = new Adaptee();
    
        public void Request()
        {
            _adaptee.SpecificRequest();
        }
    }
    
  • Мост (Bridge): Разделяет абстракцию и ее реализацию так, чтобы они могли изменяться независимо.
  • Компоновщик (Composite): Позволяет сгруппировать объекты в древовидную структуру и работать с ними как с индивидуальными объектами.
  • Декоратор (Decorator): Динамически добавляет новые обязанности объекту. Является гибкой альтернативой созданию подклассов для расширения функциональности.
  • Фасад (Facade): Предоставляет унифицированный интерфейс к набору интерфейсов в подсистеме. Фасад определяет высокоуровневый интерфейс, упрощающий подсистему.
    // Часть подсистемы 1
    public class SubsystemA
    {
        public void OperationA()
        {
            // ...
        }
    }
    
    // Часть подсистемы 2
    public class SubsystemB
    {
        public void OperationB()
        {
            // ...
        }
    }
    
    // Фасад
    public class Facade
    {
        private readonly SubsystemA subsystemA = new SubsystemA();
        private readonly SubsystemB subsystemB = new SubsystemB();
    
        public void SimplifiedOperation()
        {
            subsystemA.OperationA();
            subsystemB.OperationB();
        }
    }
    
  • Приспособленец (Flyweight): Позволяет использовать множество мелких объектов совместно, тем самым уменьшая расходы на память.
  • Заместитель (Proxy): Предоставляет суррогат или заполнитель для другого объекта для управления доступом к нему.

Поведенческие паттерны:

  • Цепочка обязанностей (Chain of Responsibility): Позволяет избежать жесткой привязки отправителя запроса к его получателю, передавая запрос по цепочке объектов. Каждый объект в цепочке решает, либо он обработает запрос, либо передаст его следующему обработчику.
    public abstract class Handler
    {
        protected Handler _nextHandler;
    
        public void SetNext(Handler handler)
        {
            _nextHandler = handler;
        }
    
        public abstract void HandleRequest(int request);
    }
    
    public class ConcreteHandler1 : Handler
    {
        public override void HandleRequest(int request)
        {
            if (request >= 0 && request < 10)
            {
                // Обработка запроса
            }
            else if (_nextHandler != null)
            {
                _nextHandler.HandleRequest(request);
            }
        }
    }
    
    public class ConcreteHandler2 : Handler
    {
        public override void HandleRequest(int request)
        {
            if (request >= 10 && request < 20)
            {
                // Обработка запроса
            }
            else if (_nextHandler != null)
            {
                _nextHandler.HandleRequest(request);
            }
        }
    }
    
  • Команда (Command): Инкапсулирует запрос как объект, позволяя параметризовать клиенты с различными запросами, ставить запросы в очередь или вести протоколы, а также поддерживать отмену операций.
  • Итератор (Iterator): Предоставляет способ последовательного доступа к элементам составного объекта без раскрытия его внутреннего представления.
  • Посредник (Mediator): Определяет объект, инкапсулирующий способ взаимодействия множества объектов. Посредник способствует слабому связыванию, избавляя объекты от необходимости явно ссылаться друг на друга, и позволяет изменять их взаимодействие независимо.
  • Хранитель (Memento): Без нарушения инкапсуляции фиксирует и выносит за пределы объекта его внутреннее состояние так, чтобы впоследствии можно было восстановить объект в этом состоянии.
  • Наблюдатель (Observer): Определяет зависимость «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются и автоматически обновляются.
    public interface IObserver
    {
        void Update(string message);
    }
    
    public class Subject
    {
        private List<IObserver> _observers = new List<IObserver>();
    
        public void Attach(IObserver observer)
        {
            _observers.Add(observer);
        }
    
        public void Detach(IObserver observer)
        {
            _observers.Remove(observer);
        }
    
        public void Notify(string message)
        {
            foreach (var observer in _observers)
            {
                observer.Update(message);
            }
        }
    
        public void SomeBusinessLogic()
        {
            // ...
            Notify("State changed");
            // ...
        }
    }
    
    public class ConcreteObserver : IObserver
    {
        public void Update(string message)
        {
            // Обработка уведомления
        }
    }
    
  • Состояние (State): Позволяет объекту изменять свое поведение в зависимости от своего внутреннего состояния. Объект как бы меняет свой класс.
  • Стратегия (Strategy): Определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет применять алгоритм независимо от клиентов, которые его используют.
  • Шаблонный метод (Template Method): Определяет скелет алгоритма в операции, оставляя некоторые шаги подклассам. Шаблонный метод позволяет подклассам переопределять шаги алгоритма, не изменяя его общую структуру.
  • Посетитель (Visitor): Представляет операцию, которая применяется к элементам структуры объектов. Посетитель позволяет определить новую операцию, не изменяя классы элементов, над которыми она оперируется.
    // Интерфейс посетителя
    public interface IVisitor
    {
        void Visit(ElementA element);
        void Visit(ElementB element);
    }
    
    // Интерфейс элемента
    public interface IElement
    {
        void Accept(IVisitor visitor);
    }
    
    // Конкретный элемент A
    public class ElementA : IElement
    {
        public void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    
        public string OperationA()
        {
            return "ElementA";
        }
    }
    
    // Конкретный элемент B
    public class ElementB : IElement
    {
        public void Accept(IVisitor visitor)
        {
            visitor.Visit(this);
        }
    
        public string OperationB()
        {
            return "ElementB";
        }
    }
    
    // Конкретный посетитель
    public class ConcreteVisitor1 : IVisitor
    {
        public void Visit(ElementA element)
        {
            // Действие для ElementA
        }
    
        public void Visit(ElementB element)
        {
            // Действие для ElementB
        }
    }