Junior
107
questionbank
Какие существуют паттерны проектирования в программировании?
Ответ от нейросети
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 } }