Python | Вопросы собесов
13.8K subscribers
36 photos
1 file
959 links
Download Telegram
📌 Что такое code cohesion & code coupling ?

💬 Спросят с вероятностью 3%

Кодовые метрики когезии (cohesion) и связи (coupling) играют ключевую роль в проектировании программного обеспечения. Давайте разберем их более подробно.

Когезия (Cohesion)

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

🤔 Почему это важно:

1️⃣ Понятность: Высокая когезия делает модули более понятными и логичными, так как они выполняют четко определенную функцию.

2️⃣ Поддерживаемость: Модули с высокой когезией легче модифицировать, тестировать и отлаживать, поскольку изменения в одном модуле менее вероятно повлияют на другие.

3️⃣ Повторное использование: Высококогезионные модули могут быть легче повторно использованы в других частях программы или в других проектах.

class Utility:
def calculate_tax(self, amount):
# Код для расчета налога
pass

def send_email(self, email, message):
# Код для отправки email
pass

def generate_report(self, data):
# Код для генерации отчета
pass


Этот класс выполняет несколько несвязанных задач, что снижает когезию.
class TaxCalculator:
def calculate_tax(self, amount):
# Код для расчета налога
pass

class EmailSender:
def send_email(self, email, message):
# Код для отправки email
pass

class ReportGenerator:
def generate_report(self, data):
# Код для генерации отчета
pass


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

Связь (Coupling)

Это мера зависимости между модулями. Низкая связь означает, что изменения в одном модуле минимально влияют на другие модули.

🤔 Почему это важно:

1️⃣ Изоляция изменений: Модули с низкой связью менее зависимы друг от друга, что упрощает внесение изменений и улучшений в код.

2️⃣ Тестируемость: Легче тестировать модули с низкой связью, так как они меньше зависят от других частей системы.

3️⃣ Повторное использование: Модули с низкой связью можно легче интегрировать в другие системы.

class OrderProcessor:
def __init__(self):
self.tax_calculator = TaxCalculator()
self.email_sender = EmailSender()

def process_order(self, order):
tax = self.tax_calculator.calculate_tax(order.amount)
self.email_sender.send_email(order.customer_email, "Order processed")


OrderProcessor сильно зависит от TaxCalculator и EmailSender.
class OrderProcessor:
def __init__(self, tax_calculator, email_sender):
self.tax_calculator = tax_calculator
self.email_sender = email_sender

def process_order(self, order):
tax = self.tax_calculator.calculate_tax(order.amount)
self.email_sender.send_email(order.customer_email, "Order processed")


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

Когезия: Это когда все части кода в модуле хорошо работают вместе и выполняют одну задачу.

Связь: Это когда модули кода мало зависят друг от друга, что делает их изменение более безопасным.

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥21
🤔 Какое значение имеет неинициализированная переменная в Python?
Anonymous Quiz
36%
None
17%
undefined
6%
null
41%
невозможно использовать неинициализированные переменные
📌 Что такое порождающий паттерн ?

💬 Спросят с вероятностью 3%

Порождающий паттерн (creational pattern) — это тип шаблонов проектирования, который предоставляет различные способы создания объектов, помогая отделить логику создания объектов от их основного использования. Порождающие паттерны помогают сделать систему более гибкой и независимой от конкретных классов, которые она использует.

🤔 Основные порождающие паттерны

1️⃣ Singleton (Одиночка)

Гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру.
      class Singleton:
_instance = None

def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance

# Использование
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True


2️⃣ Factory Method (Фабричный метод)

Определяет интерфейс для создания объектов, но позволяет подклассам изменять тип создаваемых объектов.
      from abc import ABC, abstractmethod

class Product(ABC):
@abstractmethod
def operation(self):
pass

class ConcreteProductA(Product):
def operation(self):
return "Result of ConcreteProductA"

class ConcreteProductB(Product):
def operation(self):
return "Result of ConcreteProductB"

class Creator(ABC):
@abstractmethod
def factory_method(self):
pass

def some_operation(self):
product = self.factory_method()
return f"Creator: The same creator's code has just worked with {product.operation()}"

class ConcreteCreatorA(Creator):
def factory_method(self):
return ConcreteProductA()

class ConcreteCreatorB(Creator):
def factory_method(self):
return ConcreteProductB()

# Использование
creator = ConcreteCreatorA()
print(creator.some_operation())

creator = ConcreteCreatorB()
print(creator.some_operation())


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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81🎉1
🤔 Какой модуль в стандартной библиотеке Python используется для работы с выражениями XPath?
Anonymous Quiz
24%
xml.dom
10%
xml.sax
33%
xml.etree.ElementTree
33%
re
👾51
Forwarded from Идущий к IT
10$ за техническое собеседование на английском языке:

1. Отправьте запись технического собеседования на английском языке файлом на этот аккаунт
2. Добавьте ссылку на вакансию или пришлите название компании и должность
3. Напишите номер кошелка USDT (Tether) на который отправить 10$

🛡 Важно:

– Запись будет использована только для сбора данных о вопросах
– Вы останетесь анонимны
– Запись нигде не будет опубликована

🤝 Условия:

– Внятный звук, различимая речь
– Допустимые профессии:
• Любые программисты
• DevOps
• Тестировщики
• Дата сайнтисты
• Бизнес/Системные аналитики
• Прожекты/Продукты
• UX/UI и продукт дизайнеры
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔4👀1
📌 Что такое абстрактная фабрика ?

💬 Спросят с вероятностью 3%

Абстрактная фабрика (Abstract Factory) — это порождающий паттерн проектирования, который предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов. Этот паттерн используется, когда система должна быть независимой от способа создания, композиции и представления своих продуктов.

🤔 Зачем она нужна?

1️⃣ Изоляция конкретных классов: Клиентский код работает с интерфейсами, что позволяет легко менять классы продуктов без изменения самого кода.

2️⃣ Семейства продуктов: Обеспечивает создание семейств связанных объектов, гарантируя их совместимость друг с другом.

3️⃣ Упрощение тестирования: Использование интерфейсов и абстрактных классов облегчает написание тестов и создание заглушек для модульного тестирования.

🤔 Как она работает?

Определяет интерфейсы для создания абстрактных продуктов. Конкретные фабрики реализуют эти интерфейсы, создавая конкретные продукты.

Рассмотрим пример абстрактной фабрики для создания семейств продуктов Chair и Sofa для разных стилей мебели (Modern и Victorian).
from abc import ABC, abstractmethod

# Абстрактные продукты
class Chair(ABC):
@abstractmethod
def sit_on(self) -> str:
pass

class Sofa(ABC):
@abstractmethod
def lie_on(self) -> str:
pass

# Конкретные продукты
class ModernChair(Chair):
def sit_on(self) -> str:
return "Sitting on a modern chair."

class VictorianChair(Chair):
def sit_on(self) -> str:
return "Sitting on a Victorian chair."

class ModernSofa(Sofa):
def lie_on(self) -> str:
return "Lying on a modern sofa."

class VictorianSofa(Sofa):
def lie_on(self) -> str:
return "Lying on a Victorian sofa."

# Абстрактная фабрика
class FurnitureFactory(ABC):
@abstractmethod
def create_chair(self) -> Chair:
pass

@abstractmethod
def create_sofa(self) -> Sofa:
pass

# Конкретные фабрики
class ModernFurnitureFactory(FurnitureFactory):
def create_chair(self) -> Chair:
return ModernChair()

def create_sofa(self) -> Sofa:
return ModernSofa()

class VictorianFurnitureFactory(FurnitureFactory):
def create_chair(self) -> Chair:
return VictorianChair()

def create_sofa(self) -> Sofa:
return VictorianSofa()

# Клиентский код
def client_code(factory: FurnitureFactory):
chair = factory.create_chair()
sofa = factory.create_sofa()

print(chair.sit_on())
print(sofa.lie_on())

# Использование
if __name__ == "__main__":
print("Modern furniture:")
client_code(ModernFurnitureFactory())

print("\nVictorian furniture:")
client_code(VictorianFurnitureFactory())


Преимущества:

1️⃣ Изоляция конкретных классов: Упрощает замену продуктовых семейств.

2️⃣ Согласованность продуктов: Обеспечивает совместимость создаваемых продуктов.

3️⃣ Легкость тестирования: Интерфейсы и абстрактные классы упрощают создание тестов.

Недостатки:

1️⃣ Сложность кода: Добавление большого количества классов и интерфейсов может усложнить структуру кода.

2️⃣ Увеличение количества кода: Необходимость создания множества подклассов.

Абстрактная фабрика помогает создавать семейств продуктов, делая код более гибким и расширяемым.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍53
📌 Что такое Построитель (Builder) ?

💬 Спросят с вероятностью 3%

Паттерн "Построитель" (Builder) — это порождающий паттерн проектирования, который позволяет создавать сложные объекты поэтапно. В отличие от других порождающих паттернов, Builder предоставляет возможность постепенно конструировать объект, контролируя процесс его создания на каждом этапе. Этот паттерн особенно полезен, когда нужно создать объект с различными конфигурациями или когда создание объекта требует много шагов.

🤔 Зачем нужен данный паттерн?

1️⃣ Управление сложностью создания объектов: Позволяет разбить процесс создания сложных объектов на более простые шаги.

2️⃣ Гибкость в создании объектов: Упрощает создание различных представлений объекта.

3️⃣ Читаемость и поддерживаемость: Делает код более читаемым и поддерживаемым за счет разделения процесса создания объекта на отдельные методы.

🤔 Как работает данный паттерн?

Паттерн состоит из следующих компонентов:

Builder: Интерфейс, определяющий методы для поэтапного создания объекта.

Concrete Builder: Конкретная реализация интерфейса Builder, создающая и собирающая части конечного продукта.

Product: Объект, который необходимо создать.

Director: Опциональный компонент, управляющий процессом создания объекта с использованием интерфейса Builder.

from abc import ABC, abstractmethod

# Продукт
class Car:
def __init__(self):
self.parts = []

def add_part(self, part):
self.parts.append(part)

def list_parts(self):
return ", ".join(self.parts)

# Интерфейс Построителя
class CarBuilder(ABC):
@abstractmethod
def produce_engine(self):
pass

@abstractmethod
def produce_wheels(self):
pass

@abstractmethod
def produce_body(self):
pass

# Конкретный Построитель
class SportsCarBuilder(CarBuilder):
def __init__(self):
self.car = Car()

def produce_engine(self):
self.car.add_part("Sport Engine")

def produce_wheels(self):
self.car.add_part("Sport Wheels")

def produce_body(self):
self.car.add_part("Sport Body")

def get_car(self):
return self.car

# Директор
class Director:
def __init__(self, builder: CarBuilder):
self._builder = builder

def construct_sports_car(self):
self._builder.produce_engine()
self._builder.produce_wheels()
self._builder.produce_body()

# Использование
if __name__ == "__main__":
builder = SportsCarBuilder()
director = Director(builder)

director.construct_sports_car()
car = builder.get_car()
print(f"Car parts: {car.list_parts()}")


Преимущества:

1️⃣ Разделение сложного конструктора на простые шаги: Каждый метод отвечает за создание определенной части продукта.

2️⃣ Поддержка различных представлений объекта: Можно использовать один и тот же процесс создания для создания различных вариаций продукта.

3️⃣ Улучшенная читаемость и поддерживаемость: Код легче понимать и изменять.

Недостатки:

1️⃣Усложнение структуры кода: Добавление новых классов и методов может усложнить проект.

2️⃣Необходимость в дополнительном коде: Требуется больше кода для реализации паттерна, особенно при создании новых конкретных построителей и продуктов.

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🤔32
📌 Что такое паттерн Заместитель (Proxy)?

💬 Спрашивают в 3% собеседований

Паттерн Заместитель (Proxy) — это структурный шаблон проектирования, который предоставляет объект, управляющий доступом к другому объекту. Этот паттерн создаёт суррогат или заместителя для другого объекта и контролирует доступ к нему.

🤔 Зачем нужен паттерн Заместитель

Паттерн Заместитель используется в следующих случаях:

1️⃣ Управление доступом: Когда необходимо контролировать доступ к ресурсу.

2️⃣ Отложенная инициализация: Когда необходимо отложить создание ресурсоёмких объектов до момента их первого использования.

3️⃣ Управление ресурсами: Для управления ресурсами, такими как память или сетевые соединения.

4️⃣ Логирование и кэширование: Для добавления дополнительной функциональности, такой как логирование или кэширование, без изменения кода основного объекта.

🤔 Типы заместителей

1️⃣ Управляющий заместитель (Virtual Proxy): Контролирует доступ к объекту, создавая его по требованию.

2️⃣ Защитный заместитель (Protection Proxy): Контролирует доступ к объекту, ограничивая права пользователей.

3️⃣ Удалённый заместитель (Remote Proxy): Управляет доступом к объекту, находящемуся в другом адресном пространстве.

4️⃣ Кэш-прокси (Cache Proxy): Кэширует результаты запросов к объекту для повышения производительности.

🤔 Как используется паттерн Заместитель

Заместитель реализует интерфейс основного объекта и перенаправляет вызовы к реальному объекту, добавляя при этом дополнительную функциональность.

🤔 Пример использования

Рассмотрим пример с удалённым заместителем, который управляет доступом к удалённому серверу.
from abc import ABC, abstractmethod

class Subject(ABC):
@abstractmethod
def request(self):
pass

class RealSubject(Subject):
def request(self):
print("Реальный объект: Обработка запроса.")

class Proxy(Subject):
def __init__(self, real_subject):
self._real_subject = real_subject

def request(self):
if self.check_access():
self._real_subject.request()
self.log_access()

def check_access(self):
print("Заместитель: Проверка доступа перед выполнением запроса.")
return True

def log_access(self):
print("Заместитель: Логирование времени запроса.")

# Клиентский код
real_subject = RealSubject()
proxy = Proxy(real_subject)

proxy.request()


В этом примере класс Proxy контролирует доступ к классу RealSubject, добавляя проверку доступа и логирование.

🤔 Подытожим

Паттерн Заместитель управляет доступом к другому объекту, предоставляя дополнительные возможности, такие как контроль доступа, отложенная инициализация, управление ресурсами, логирование и кэширование.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥31
📌 Что такое Фабричный метод (Factory method) ?

💬 Спросят с вероятностью 3%

Фабричный метод (Factory Method) — это порождающий паттерн проектирования, который предоставляет интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов. Этот паттерн используется, когда классу заранее неизвестно, объекты каких классов ему нужно создавать, либо он хочет дать возможность своим подклассам выбирать тип создаваемых объектов.

🤔 Зачем нужен данный паттерн?

1️⃣ Изоляция создания объектов: Позволяет суперклассу делегировать создание объектов подклассам, изолируя логику создания объектов от основной логики программы.

2️⃣ Расширяемость: Упрощает добавление новых типов объектов, не изменяя существующий код.

3️⃣ Упрощение тестирования: Легче тестировать классы, так как создание объектов сосредоточено в одном месте.

🤔Как работает данный паттерн?

Паттерн включает в себя следующие компоненты:

Продукт (Product): Интерфейс или абстрактный класс для объектов, которые будут создаваться.

Конкретный продукт (ConcreteProduct): Конкретные реализации продукта.

Создатель (Creator): Абстрактный класс или интерфейс с объявлением фабричного метода.

Конкретный создатель (ConcreteCreator): Классы, которые реализуют фабричный метод для создания конкретных продуктов.

from abc import ABC, abstractmethod

# Продукт
class Transport(ABC):
@abstractmethod
def deliver(self) -> str:
pass

# Конкретные продукты
class Truck(Transport):
def deliver(self) -> str:
return "Deliver by land in a box."

class Ship(Transport):
def deliver(self) -> str:
return "Deliver by sea in a container."

# Создатель
class Logistics(ABC):
@abstractmethod
def create_transport(self) -> Transport:
pass

def plan_delivery(self) -> str:
transport = self.create_transport()
return transport.deliver()

# Конкретные создатели
class RoadLogistics(Logistics):
def create_transport(self) -> Transport:
return Truck()

class SeaLogistics(Logistics):
def create_transport(self) -> Transport:
return Ship()

# Использование
def client_code(logistics: Logistics):
print(logistics.plan_delivery())

if __name__ == "__main__":
print("App: Launched with the RoadLogistics.")
client_code(RoadLogistics())

print("\nApp: Launched with the SeaLogistics.")
client_code(SeaLogistics())


Преимущества:

1️⃣ Изоляция создания объектов: Создание объектов делегируется подклассам, что изолирует основной код от логики создания объектов.

2️⃣ Расширяемость: Легко добавлять новые продукты, не изменяя существующий код.

3️⃣ Упрощение тестирования: Легко подменять конкретные реализации продуктов для тестирования.

Недостатки:

1️⃣ Усложнение кода: Требует создания большого количества дополнительных классов.

2️⃣ Поддержка иерархии классов: Может усложнить систему, если классы продуктов и создателей становятся слишком сложными.

Паттерн "Фабричный метод" позволяет создавать объекты через интерфейс, делегируя создание конкретных объектов подклассам, что делает код более гибким и расширяемым.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍71
📌 Что такое паттерн Прототип (Prototype) ?

💬 Спросят с вероятностью 3%

Паттерн "Прототип" (Prototype) — это порождающий паттерн проектирования, который позволяет копировать объекты, не прибегая к их конкретным классам. Он предоставляет механизм для создания новых объектов путем клонирования уже существующих экземпляров-прототипов. Этот паттерн полезен, когда создание объектов требует больших затрат (например, вычислительных или временных), и проще клонировать существующий объект.

🤔 Зачем нужен данный паттерн?

1️⃣ Экономия ресурсов: Избегает затрат на создание нового объекта с нуля, используя существующий объект как шаблон.

2️⃣ Изоляция клиентов от классов продуктов: Позволяет создавать новые объекты без привязки к конкретным классам, что повышает гибкость системы.

3️⃣ Упрощение процесса создания сложных объектов: Легко создавать объекты со сложной конфигурацией, клонируя уже настроенные экземпляры.

🤔 Как работает данный паттерн?

Паттерн включает в себя следующие компоненты:

Прототип (Prototype): Интерфейс с методом клонирования, который будет реализован конкретными классами.

Конкретный прототип (ConcretePrototype): Классы, которые реализуют метод клонирования для создания копий своих объектов.

Клиент (Client): Использует метод клонирования для создания новых объектов.

import copy
from abc import ABC, abstractmethod

# Прототип
class Prototype(ABC):
@abstractmethod
def clone(self):
pass

# Конкретный прототип
class ConcretePrototype1(Prototype):
def __init__(self, field):
self.field = field

def clone(self):
return copy.deepcopy(self)

def __str__(self):
return f"ConcretePrototype1 with field: {self.field}"

class ConcretePrototype2(Prototype):
def __init__(self, field):
self.field = field

def clone(self):
return copy.deepcopy(self)

def __str__(self):
return f"ConcretePrototype2 with field: {self.field}"

# Использование
if __name__ == "__main__":
prototype1 = ConcretePrototype1("Value1")
prototype2 = ConcretePrototype2("Value2")

clone1 = prototype1.clone()
clone2 = prototype2.clone()

print(prototype1) # ConcretePrototype1 with field: Value1
print(clone1) # ConcretePrototype1 with field: Value1
print(prototype2) # ConcretePrototype2 with field: Value2
print(clone2) # ConcretePrototype2 with field: Value2


Преимущества:

1️⃣ Экономия ресурсов: Быстрое создание новых объектов путем клонирования.

2️⃣ Гибкость: Легко создавать объекты без привязки к конкретным классам.

3️⃣ Упрощение создания сложных объектов: Позволяет клонировать уже настроенные объекты.

Недостатки:

1️⃣ Сложность реализации клонирования: Необходимо правильно реализовать глубокое или поверхностное копирование, что может быть сложно.

2️⃣ Проблемы с копированием объектов: Некоторые объекты могут содержать ссылки на другие, что требует сложных механизмов для правильного клонирования.

Паттерн "Прототип" позволяет быстро и эффективно создавать новые объекты путем клонирования существующих, что упрощает процесс создания сложных объектов и экономит ресурсы.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
📌 Что такое Структурные (Structural) паттерны ?

💬 Спросят с вероятностью 3%

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

🤔 Основные паттерны

1️⃣ Adapter (Адаптер):

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

Использование старого интерфейса библиотеки в новом проекте.

      class OldPrinter:
def print_old(self, text):
print(f"OldPrinter: {text}")

class NewPrinterInterface:
def print(self, text):
pass

class PrinterAdapter(NewPrinterInterface):
def __init__(self, old_printer):
self.old_printer = old_printer

def print(self, text):
self.old_printer.print_old(text)

old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)
adapter.print("Hello, world!")


2️⃣ Bridge (Мост):

Разделяет абстракцию и её реализацию так, чтобы они могли изменяться независимо друг от друга.

Разделение логики рисования фигуры и конкретных реализаций рисования.

      class DrawingAPI(ABC):
@abstractmethod
def draw_circle(self, x, y, radius):
pass

class DrawingAPI1(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API1.circle at {x}:{y} radius {radius}")

class DrawingAPI2(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API2.circle at {x}:{y} radius {radius}")

class Circle:
def __init__(self, x, y, radius, drawing_api):
self.x = x
self.y = y
self.radius = radius
self.drawing_api = drawing_api

def draw(self):
self.drawing_api.draw_circle(self.x, self.y, self.radius)

circle1 = Circle(1, 2, 3, DrawingAPI1())
circle2 = Circle(5, 7, 11, DrawingAPI2())

circle1.draw()
circle2.draw()


3️⃣ Composite (Компоновщик):

Составляет объекты в древовидные структуры для представления иерархий "часть-целое". Позволяет клиентам одинаково обращаться как с отдельными объектами, так и с группами объектов.

Организация структуры компании, где у нас есть как сотрудники, так и отделы.

      class Employee:
def __init__(self, name, position):
self.name = name
self.position = position
self.subordinates = []

def add(self, employee):
self.subordinates.append(employee)

def remove(self, employee):
self.subordinates.remove(employee)

def display(self, indent=0):
print(" " * indent + f"{self.position}: {self.name}")
for subordinate in self.subordinates:
subordinate.display(indent + 2)

ceo = Employee("John", "CEO")
head_sales = Employee("Robert", "Head of Sales")
sales_exec1 = Employee("Laura", "Sales Executive")
sales_exec2 = Employee("Bob", "Sales Executive")

ceo.add(head_sales)
head_sales.add(sales_exec1)
head_sales.add(sales_exec2)

ceo.display()

Структурные паттерны проектирования помогают организовать классы и объекты в крупные структуры, повышая гибкость и расширяемость системы.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍102🔥2
📌 Что такое паттерн Адаптер (Adapter) ?

💬 Спросят с вероятностью 3%

Паттерн "Адаптер" (Adapter) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он служит посредником, преобразуя интерфейс одного класса в интерфейс, который ожидает клиентский код.

😜 Зачем нужен данный паттерн?

1️⃣ Совместимость интерфейсов: Позволяет интегрировать классы с несовместимыми интерфейсами, не изменяя их.

2️⃣ Повторное использование: Упрощает повторное использование существующих классов, предоставляя требуемый интерфейс.

3️⃣ Упрощение кода: Упрощает клиентский код, устраняя необходимость изменений при интеграции новых классов.

🤔 Как работает данный паттерн?

Паттерн включает следующие компоненты:

Целевой интерфейс (Target): Интерфейс, который ожидает клиентский код.

Адаптируемый класс (Adaptee): Класс с несовместимым интерфейсом, который нужно адаптировать.

Адаптер (Adapter): Класс, который преобразует интерфейс Adaptee в интерфейс Target.

# Целевой интерфейс (Target)
class PrinterInterface:
def print(self, text):
pass

# Адаптируемый класс (Adaptee)
class OldPrinter:
def print_old(self, text):
print(f"OldPrinter: {text}")

# Адаптер (Adapter)
class PrinterAdapter(PrinterInterface):
def __init__(self, old_printer):
self.old_printer = old_printer

def print(self, text):
self.old_printer.print_old(text)

# Клиентский код
def client_code(printer: PrinterInterface):
printer.print("Hello, world!")

# Использование
old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)
client_code(adapter)


Преимущества:

1️⃣ Повышенная совместимость: Позволяет работать с классами, которые иначе были бы несовместимыми.

2️⃣ Упрощение интеграции: Легко интегрировать старые классы с новым кодом без изменения исходных классов.

3️⃣ Поддержка существующего кода: Минимизирует изменения в клиентском коде.

Недостатки:

1️⃣ Дополнительная сложность: Введение адаптера добавляет новый слой абстракции, что может усложнить структуру кода.

2️⃣ Ограниченная производительность: Использование адаптера может в некоторых случаях влиять на производительность из-за дополнительного уровня косвенности.

🤔 Виды:

1️⃣ Класс-адаптер (Class Adapter):

Реализуется через наследование.

Преобразует интерфейс с помощью множественного наследования.

Ограничение: Работает только с адаптируемым классом и его подклассами.

2️⃣ Объект-адаптер (Object Adapter):

Реализуется через композицию.

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

Более гибкий, так как может работать с любыми классами, поддерживающими целевой интерфейс.

Класс-адаптер:
class OldPrinter:
def print_old(self, text):
print(f"OldPrinter: {text}")

class PrinterAdapter(OldPrinter, PrinterInterface):
def print(self, text):
self.print_old(text)

# Использование
adapter = PrinterAdapter()
client_code(adapter)


Объект-адаптер:
class PrinterAdapter(PrinterInterface):
def __init__(self, old_printer):
self.old_printer = old_printer

def print(self, text):
self.old_printer.print_old(text)

# Использование
old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)
client_code(adapter)


Паттерн "Адаптер" является мощным инструментом для интеграции старых систем с новыми требованиями, обеспечивая гибкость и повторное использование существующих классов без изменения их исходного кода.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍122
📌 Что такое паттерн Мост (Bridge) ?

💬 Спросят с вероятностью 3%

Паттерн "Мост" (Bridge) — это структурный паттерн проектирования, который разделяет абстракцию и её реализацию так, чтобы они могли изменяться независимо друг от друга. Он используется для разделения сложных систем на части, которые можно развивать, изменять и использовать независимо.

🤔 Зачем нужен данный паттерн?

1️⃣ Разделение ответственности: Позволяет разделить абстрактную часть системы (например, интерфейс) и конкретную реализацию.

2️⃣ Упрощение изменений: Изменения в абстракции или реализации не требуют изменений в другой части.

3️⃣ Гибкость и расширяемость: Упрощает добавление новых абстракций и реализаций без изменения существующего кода.

🤔 Как работает данный паттерн?

Паттерн включает следующие компоненты:

Абстракция (Abstraction): Определяет интерфейс и содержит ссылку на объект реализации.

Расширенная абстракция (Refined Abstraction): Расширяет интерфейс абстракции.

Интерфейс реализации (Implementor): Определяет интерфейс для всех реализаций.

Конкретная реализация (Concrete Implementor): Реализует интерфейс реализации.

from abc import ABC, abstractmethod

# Интерфейс реализации
class DrawingAPI(ABC):
@abstractmethod
def draw_circle(self, x, y, radius):
pass

# Конкретные реализации
class DrawingAPI1(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API1.circle at {x}:{y} radius {radius}")

class DrawingAPI2(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API2.circle at {x}:{y} radius {radius}")

# Абстракция
class Shape(ABC):
def __init__(self, drawing_api):
self.drawing_api = drawing_api

@abstractmethod
def draw(self):
pass

@abstractmethod
def resize(self, factor):
pass

# Расширенная абстракция
class CircleShape(Shape):
def __init__(self, x, y, radius, drawing_api):
super().__init__(drawing_api)
self.x = x
self.y = y
self.radius = radius

def draw(self):
self.drawing_api.draw_circle(self.x, self.y, self.radius)

def resize(self, factor):
self.radius *= factor

# Использование
circle1 = CircleShape(1, 2, 3, DrawingAPI1())
circle2 = CircleShape(5, 7, 11, DrawingAPI2())

circle1.draw()
circle2.draw()

circle1.resize(2)
circle1.draw()


Преимущества:

1️⃣ Разделение кода: Абстракция и реализация могут изменяться независимо.

2️⃣ Уменьшение связности: Уменьшает зависимость между абстракцией и реализацией.

3️⃣ Гибкость: Легко добавлять новые абстракции и реализации.

Недостатки:

1️⃣ Сложность структуры: Увеличение количества классов и усложнение структуры кода.

2️⃣ Дополнительный уровень косвенности: Может затруднить понимание кода из-за дополнительных уровней абстракции.

🤔 Когда использовать данный паттерн?

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

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

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

Паттерн "Мост" обеспечивает гибкость в проектировании сложных систем, разделяя их на независимые части, что облегчает их развитие и поддержку.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
📌 Что такое паттерн Компоновщик (Composite) ?

💬 Спросят с вероятностью 3%

Паттерн "Компоновщик" (Composite) — это структурный паттерн проектирования, который позволяет сгруппировать объекты в древовидные структуры для представления иерархий "часть-целое". Этот паттерн позволяет клиенту одинаково работать как с отдельными объектами, так и с группами объектов.

🤔 Зачем нужен данный паттерн?

1️⃣ Упрощение клиентского кода: Клиентский код может работать с объектами и их контейнерами одинаково, без необходимости в различении их типов.

2️⃣ Гибкость структуры: Позволяет создавать сложные иерархии объектов динамически.

3️⃣ Повторное использование кода: Легче добавлять новые типы компонентов, не меняя существующий код.

🤔 Как работает данный паттерн?

Паттерн включает следующие компоненты:

Компонент (Component): Определяет общий интерфейс для всех объектов в композиции.

Лист (Leaf): Представляет отдельные объекты, которые не могут иметь подкомпонентов.

Контейнер (Composite): Представляет объекты, которые могут содержать другие компоненты (листы или контейнеры).

from abc import ABC, abstractmethod

# Компонент
class Employee(ABC):
@abstractmethod
def show_details(self):
pass

# Лист
class Developer(Employee):
def __init__(self, name, position):
self.name = name
self.position = position

def show_details(self):
print(f"{self.position}: {self.name}")

class Designer(Employee):
def __init__(self, name, position):
self.name = name
self.position = position

def show_details(self):
print(f"{self.position}: {self.name}")

# Контейнер
class Organization(Employee):
def __init__(self):
self.employees = []

def add(self, employee):
self.employees.append(employee)

def remove(self, employee):
self.employees.remove(employee)

def show_details(self):
for employee in self.employees:
employee.show_details()

# Использование
dev1 = Developer("John Doe", "Senior Developer")
dev2 = Developer("Jane Smith", "Junior Developer")
designer = Designer("Emily Davis", "Senior Designer")

org = Organization()
org.add(dev1)
org.add(dev2)
org.add(designer)

org.show_details()


Преимущества:

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

2️⃣ Гибкость: Легко добавлять новые компоненты и контейнеры.

3️⃣ Простота добавления новых элементов: Новые типы компонентов можно добавлять, не изменяя существующий код.

Недостатки:

1️⃣ Сложность управления: Может быть сложно управлять, если структура становится слишком глубокой или разветвленной.

2️⃣ Трудность реализации: Реализация может быть сложной, особенно когда требуется поддерживать разные виды операций над компонентами.

🤔 Когда использовать данный паттерн?

Когда требуется представлять иерархические структуры объектов.

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

Когда нужно упростить работу с объектами, представляющими части целого.

Паттерн "Компоновщик" является мощным инструментом для работы с древовидными структурами данных, позволяя легко манипулировать и управлять как отдельными объектами, так и их группами.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
📌 Что такое паттерн Фасад (Facade) ?

💬 Спросят с вероятностью 3%

Паттерн "Фасад" (Facade) — это структурный паттерн проектирования, который предоставляет унифицированный интерфейс для взаимодействия с набором интерфейсов в подсистеме. Фасад определяет высокоуровневый интерфейс, упрощающий работу с более сложной подсистемой.

🤔 Зачем нужен данный паттерн?

1️⃣ Упрощение использования подсистемы: Позволяет клиентам взаимодействовать с подсистемой через простой и понятный интерфейс.

2️⃣ Сокрытие сложности: Скрывает детали реализации и организацию сложной подсистемы от клиентов.

3️⃣ Снижение зависимости: Уменьшает количество зависимостей между клиентами и подсистемой, упрощая поддержку и изменение системы.

🤔 Как работает данный паттерн?

Паттерн включает следующие компоненты:

Фасад (Facade): Класс, предоставляющий упрощенный интерфейс для взаимодействия с подсистемой.

Подсистема (Subsystem): Один или несколько классов, выполняющих сложную работу. Подсистема не знает о существовании фасада и работает автономно.

class Amplifier:
def on(self):
print("Amplifier on")

def set_volume(self, volume):
print(f"Amplifier volume set to {volume}")

def off(self):
print("Amplifier off")

class DVDPlayer:
def on(self):
print("DVD Player on")

def play(self, movie):
print(f"Playing movie: {movie}")

def stop(self):
print("DVD Player stopped")

def off(self):
print("DVD Player off")

class Projector:
def on(self):
print("Projector on")

def set_input(self, input):
print(f"Projector input set to {input}")

def off(self):
print("Projector off")

# Фасад
class HomeTheaterFacade:
def __init__(self, amp, dvd, projector):
self.amp = amp
self.dvd = dvd
self.projector = projector

def watch_movie(self, movie):
print("Get ready to watch a movie...")
self.amp.on()
self.amp.set_volume(5)
self.dvd.on()
self.dvd.play(movie)
self.projector.on()
self.projector.set_input("DVD")

def end_movie(self):
print("Shutting movie theater down...")
self.amp.off()
self.dvd.stop()
self.dvd.off()
self.projector.off()

# Использование
amp = Amplifier()
dvd = DVDPlayer()
projector = Projector()

home_theater = HomeTheaterFacade(amp, dvd, projector)
home_theater.watch_movie("Inception")
home_theater.end_movie()


Преимущества:

1️⃣ Упрощение использования: Предоставляет простой интерфейс для сложной подсистемы.

2️⃣ Сокрытие деталей реализации: Скрывает внутреннюю структуру подсистемы, делая её использование проще и понятнее.

3️⃣ Снижение зависимости: Уменьшает количество зависимостей между клиентами и подсистемой.

Недостатки:

1️⃣ Ограниченная функциональность: Может ограничивать функциональность, предоставляемую подсистемой, если фасад предоставляет слишком упрощенный интерфейс.

2️⃣ Дополнительный слой абстракции: Введение фасада добавляет дополнительный слой кода, что может усложнить систему в некоторых случаях.

🤔 Когда использовать данный паттерн?

Когда нужно предоставить простой интерфейс для сложной подсистемы.

Когда нужно сократить количество зависимостей между клиентами и подсистемой.

Когда нужно организовать код и уменьшить связность в системе.

Паттерн "Фасад" является полезным инструментом для упрощения взаимодействия с сложными подсистемами, скрывая их внутреннюю сложность и предоставляя удобный интерфейс для клиентов.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
📌 Что такое паттерн Приспособленец (Flyweight) ?

💬 Спросят с вероятностью 3%

Паттерн "Приспособленец" (Flyweight) — это структурный паттерн проектирования, который позволяет эффективно поддерживать большое количество мелких объектов, минимизируя использование памяти. Это достигается путем совместного использования общего состояния объектов, вместо хранения одинаковых данных в каждом объекте.

🤔 Зачем нужен данный паттерн?

1️⃣ Экономия памяти: Позволяет хранить большое количество объектов, используя меньше памяти за счет разделения общего состояния между ними.

2️⃣ Увеличение производительности: Уменьшение затрат на память может также улучшить производительность системы, особенно если создание объектов является дорогостоящей операцией.

🤔 Как работает данный паттерн?

Паттерн "Приспособленец" разделяет состояние объекта на:

Внутреннее состояние (Intrinsic State): Состояние, которое является одинаковым для многих объектов и может быть разделено между ними.

Внешнее состояние (Extrinsic State): Состояние, которое уникально для каждого объекта и передается в методы.

class Flyweight:
def __init__(self, intrinsic_state):
self.intrinsic_state = intrinsic_state

def operation(self, extrinsic_state):
print(f"Flyweight: Intrinsic state = {self.intrinsic_state}, Extrinsic state = {extrinsic_state}")

class FlyweightFactory:
_flyweights = {}

def get_flyweight(self, intrinsic_state):
if intrinsic_state not in self._flyweights:
self._flyweights[intrinsic_state] = Flyweight(intrinsic_state)
return self._flyweights[intrinsic_state]

# Клиентский код
factory = FlyweightFactory()

# Создание и использование приспособленцев
flyweight1 = factory.get_flyweight("Shared State A")
flyweight1.operation("Unique State 1")

flyweight2 = factory.get_flyweight("Shared State B")
flyweight2.operation("Unique State 2")

flyweight3 = factory.get_flyweight("Shared State A")
flyweight3.operation("Unique State 3")

# Проверка совместного использования приспособленцев
print(flyweight1 is flyweight3) # True


Преимущества:

1️⃣ Экономия памяти: Значительно уменьшает количество памяти, необходимое для хранения большого количества объектов.

2️⃣ Увеличение
производительности
: Снижение затрат на создание и хранение объектов может улучшить общую производительность системы.

Недостатки:

1️⃣ Сложность реализации: Требует тщательной разработки для правильного разделения внутреннего и внешнего состояния.

2️⃣ Снижение читабельности кода: Использование внешнего состояния может сделать код менее понятным и трудным для сопровождения.

🤔 Когда использовать данный паттерн?

Когда система должна эффективно работать с большим количеством объектов.

Когда значительная часть состояния объектов может быть разделена.

Когда создание объектов является дорогостоящей операцией и использование памяти критично.

Паттерн "Приспособленец" является мощным инструментом для оптимизации использования памяти и повышения производительности в системах, работающих с большим количеством однотипных объектов.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
📌 Что такое паттерн Заместитель (Proxy) ?

💬 Спросят с вероятностью 3%

Паттерн "Заместитель" (Proxy) — это структурный паттерн проектирования, который предоставляет суррогатный или заместительный объект для другого объекта с целью контроля доступа к нему. Заместитель выполняет функции обёртки или посредника, передавая вызовы к реальному объекту и добавляя к ним дополнительную логику.

🤔 Зачем нужен данный паттерн?

1️⃣ Контроль доступа: Позволяет управлять доступом к объекту, добавляя проверки и ограничения.

2️⃣ Ленивая инициализация: Позволяет откладывать создание и инициализацию ресурсоёмких объектов до момента, когда они действительно понадобятся.

3️⃣ Удалённый доступ: Обеспечивает взаимодействие с удалёнными объектами, как будто они локальные.

4️⃣ Логирование и кэширование: Добавляет дополнительные действия, такие как логирование или кэширование, при доступе к объекту.

🤔 Как работает данный паттерн?

Паттерн "Заместитель" включает следующие компоненты:

Реальный субъект (RealSubject): Класс, представляющий реальный объект, к которому требуется контролируемый доступ.

Интерфейс (Subject): Общий интерфейс для реального субъекта и заместителя, позволяющий заместителю подменять реальный объект.

Заместитель (Proxy): Класс, который реализует интерфейс и содержит ссылку на реальный объект. Он перехватывает вызовы к реальному объекту и может добавлять к ним дополнительную логику.

from abc import ABC, abstractmethod

# Интерфейс (Subject)
class Subject(ABC):
@abstractmethod
def request(self):
pass

# Реальный субъект (RealSubject)
class RealSubject(Subject):
def request(self):
print("RealSubject: Handling request.")

# Заместитель (Proxy)
class Proxy(Subject):
def __init__(self, real_subject):
self._real_subject = real_subject

def request(self):
if self.check_access():
self._real_subject.request()
self.log_access()

def check_access(self):
print("Proxy: Checking access prior to firing a real request.")
return True

def log_access(self):
print("Proxy: Logging the time of request.")

# Клиентский код
def client_code(subject: Subject):
subject.request()

# Использование
real_subject = RealSubject()
proxy = Proxy(real_subject)
client_code(proxy)


Преимущества:

1️⃣ Контроль доступа: Позволяет легко управлять доступом к реальному объекту.

2️⃣ Ленивая инициализация: Экономит ресурсы, откладывая создание объектов до необходимости.

3️⃣ Логирование и кэширование: Обеспечивает функциональность без изменения реального объекта.

4️⃣ Удалённый доступ: Упрощает взаимодействие с удалёнными объектами.

Недостатки:

1️⃣ Усложнение кода: Добавляет дополнительные классы и слои абстракции, что может усложнить систему.

2️⃣ Снижение производительности: Введение дополнительных проверок и логики может повлиять на производительность.

🤔 Виды:

1️⃣ Remote Proxy: Управляет взаимодействием с удалённым объектом.

2️⃣ Virtual Proxy: Управляет доступом к ресурсоёмкому объекту, создавая его по требованию.

3️⃣ Protection Proxy: Контролирует доступ к объекту, обеспечивая безопасность.

4️⃣ Smart Proxy: Добавляет дополнительную функциональность при доступе к объекту (например, рефлекторное считывание и запись).

🤔 Когда использовать данный паттерн?

Когда нужно контролировать доступ к ресурсоёмкому или удалённому объекту.

Когда требуется добавить дополнительные операции при доступе к объекту.

Когда необходимо обеспечить безопасность и контроль над доступом к объекту.

Паттерн "Заместитель" является мощным инструментом для управления доступом к объектам, добавления логики и улучшения производительности в определённых сценариях.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥1
📌 Что такое поведенческие паттерны ?

💬 Спрашивают в 3% собеседований

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

🤔 Основные паттерны

1️⃣ Chain of Responsibility (Цепочка обязанностей):

Позволяет передавать запрос последовательно по цепочке обработчиков, пока один из них не обработает запрос.

Система логирования, где различные уровни логов (информация, предупреждение, ошибка) обрабатываются разными обработчиками.

      class Handler(ABC):
def __init__(self, successor=None):
self._successor = successor

@abstractmethod
def handle(self, request):
pass

class ConcreteHandler1(Handler):
def handle(self, request):
if request == "Condition1":
print("Handled by ConcreteHandler1")
elif self._successor:
self._successor.handle(request)

class ConcreteHandler2(Handler):
def handle(self, request):
if request == "Condition2":
print("Handled by ConcreteHandler2")
elif self._successor:
self._successor.handle(request)

# Использование
handler = ConcreteHandler1(ConcreteHandler2())
handler.handle("Condition2")


2️⃣ Command (Команда):

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

Система меню, где каждый пункт меню представляет команду.

      class Command(ABC):
@abstractmethod
def execute(self):
pass

class Light:
def on(self):
print("Light is ON")

def off(self):
print("Light is OFF")

class LightOnCommand(Command):
def __init__(self, light):
self._light = light

def execute(self):
self._light.on()

class LightOffCommand(Command):
def __init__(self, light):
self._light = light

def execute(self):
self._light.off()

# Использование
light = Light()
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)

light_on.execute()
light_off.execute()


3️⃣ Iterator (Итератор):

Предоставляет способ последовательного доступа ко всем элементам коллекции без раскрытия её внутреннего представления.

Обход элементов массива или связного списка.

      class Iterator(ABC):
@abstractmethod
def next(self):
pass

@abstractmethod
def has_next(self):
pass

class ConcreteIterator(Iterator):
def __init__(self, collection):
self._collection = collection
self._index = 0

def next(self):
item = self._collection[self._index]
self._index += 1
return item

def has_next(self):
return self._index < len(self._collection)

# Использование
collection = [1, 2, 3, 4]
iterator = ConcreteIterator(collection)

while iterator.has_next():
print(iterator.next())

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
📌 Что такое Цепочка ответственности (Chain of responsobility) ?

💬 Спрашивают в 3% собеседований

Цепочка ответственности (Chain of Responsibility) — это поведенческий паттерн проектирования, который позволяет передавать запросы последовательно по цепочке обработчиков. Каждый обработчик решает, может ли он обработать запрос самостоятельно, либо передает его следующему обработчику в цепочке.

🤔 Зачем нужен данный паттерн?

1️⃣ Изоляция отправителя запроса от его получателей: Отправитель запроса не не знает, какой именно обработчик его обработает.

2️⃣ Гибкость в распределении обязанностей: Легко менять цепочку обработчиков и их последовательность.

3️⃣ Уменьшение зависимости между объектами: Позволяет избежать жёсткой привязки отправителей к конкретным обработчикам.

🤔 Как работает данный паттерн?

Паттерн включает следующие компоненты:

Обработчик (Handler): Интерфейс или абстрактный класс, определяющий метод для обработки запроса и ссылку на следующий обработчик в цепочке.

Конкретные обработчики (ConcreteHandler): Классы, реализующие интерфейс обработчика. Каждый обработчик решает, может ли он обработать запрос, либо передает его следующему обработчику.

Клиент (Client): Отправляет запрос первому обработчику в цепочке.

from abc import ABC, abstractmethod

# Абстрактный обработчик
class Handler(ABC):
def __init__(self, successor=None):
self._successor = successor

@abstractmethod
def handle(self, request):
pass

# Конкретный обработчик 1
class ConcreteHandler1(Handler):
def handle(self, request):
if request == "Condition1":
print("Handled by ConcreteHandler1")
elif self._successor:
self._successor.handle(request)

# Конкретный обработчик 2
class ConcreteHandler2(Handler):
def handle(self, request):
if request == "Condition2":
print("Handled by ConcreteHandler2")
elif self._successor:
self._successor.handle(request)

# Клиентский код
def client_code(handler, request):
handler.handle(request)

# Создание цепочки обработчиков
handler1 = ConcreteHandler1()
handler2 = ConcreteHandler2(handler1)

# Использование
client_code(handler2, "Condition1") # Handled by ConcreteHandler1
client_code(handler2, "Condition2") # Handled by ConcreteHandler2
client_code(handler2, "Condition3") # Ничего не происходит, так как запрос не обработан


🤔 Преимущества:

1️⃣ Гибкость в распределении обязанностей: Легко изменять цепочку обработчиков.

2️⃣ Изоляция отправителя запроса от его получателей: Отправитель запроса не знает, какой именно обработчик его обработает.

3️⃣ Уменьшение зависимости между объектами: Меньше жёстких привязок между отправителями и получателями запросов.

🤔 Недостатки:

1️⃣ Неопределенность обработки: Запрос может остаться необработанным, если ни один из обработчиков не сможет его обработать.

2️⃣ Сложность отладки: Из-за передачи запроса по цепочке может быть сложно определить, где именно он был обработан или отклонен.

🤔 Когда использовать данный паттерн?

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

Когда набор обработчиков и их порядок должен легко изменяться.

Когда необходимо избежать жёсткой привязки отправителей запросов к их получателям.

Паттерн "Цепочка ответственности" является мощным инструментом для гибкого и динамичного распределения обязанностей по обработке запросов в системе.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41