Python | Вопросы собесов
13.8K subscribers
35 photos
1 file
959 links
Download Telegram
📌 Что такое Фабричный метод (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
🤔 Какой модуль используется для работы с многопоточностью в Python?
Anonymous Quiz
30%
asyncio
20%
multiprocessing
49%
threading
2%
concurrent
📌 Что такое паттерн Команда (Command) ?

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

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

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

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

2️⃣ Разделение ответственности: Отделяет отправителя запроса от объекта, выполняющего запрос.

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

4️⃣ Параметризация объектов: Позволяет параметризовать объекты с операциями.

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

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

Команда (Command): Интерфейс с методом execute.

Конкретные команды (ConcreteCommand): Реализуют интерфейс команды, инкапсулируя действия для конкретного запроса.

Получатель (Receiver): Объект, который выполняет действие по запросу.

Отправитель (Invoker): Объект, который инициирует выполнение команды.

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

from abc import ABC, abstractmethod

# Интерфейс команды
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()

# Отправитель
class RemoteControl:
def __init__(self):
self._commands = {}

def set_command(self, button, command):
self._commands[button] = command

def press_button(self, button):
if button in self._commands:
self._commands[button].execute()
else:
print("No command assigned to this button")

# Клиентский код
light = Light()
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)

remote = RemoteControl()
remote.set_command("ON", light_on)
remote.set_command("OFF", light_off)

remote.press_button("ON") # Light is ON
remote.press_button("OFF") # Light is OFF
remote.press_button("UNASSIGNED") # No command assigned to this button


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

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

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

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

4️⃣ Разделение ответственности: Разделяет ответственность между отправителем и получателем.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1️⃣ Анализ и выполнение текстов: Позволяет анализировать и выполнять предложения на специальном языке.

2️⃣ Упрощение грамматики: Разделяет грамматику языка и её интерпретацию, что упрощает понимание и изменение правил языка.

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

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

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

Контекст (Context): Содержит информацию, глобальную для всех интерпретаторов.

Абстрактное выражение (AbstractExpression): Интерфейс или абстрактный класс для всех выражений.

Конкретные выражения (TerminalExpression и NonTerminalExpression): Классы, реализующие конкретные правила грамматики.

Клиент (Client): Построит и использует объектную структуру абстрактного синтаксического дерева.

from abc import ABC, abstractmethod

# Контекст (необязательный компонент)
class Context:
pass

# Абстрактное выражение
class Expression(ABC):
@abstractmethod
def interpret(self, context):
pass

# Терминальное выражение (число)
class Number(Expression):
def __init__(self, value):
self.value = value

def interpret(self, context):
return self.value

# Нетерминальное выражение (сложение)
class Add(Expression):
def __init__(self, left, right):
self.left = left
self.right = right

def interpret(self, context):
return self.left.interpret(context) + self.right.interpret(context)

# Нетерминальное выражение (вычитание)
class Subtract(Expression):
def __init__(self, left, right):
self.left = left
self.right = right

def interpret(self, context):
return self.left.interpret(context) - self.right.interpret(context)

# Клиентский код
def main():
# Построение выражения: 1 + 2 - 3
expression = Subtract(Add(Number(1), Number(2)), Number(3))
context = Context() # Контекст может использоваться для передачи информации
result = expression.interpret(context)
print(result) # 0

if __name__ == "__main__":
main()


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

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

2️⃣ Четкая структура: Грамматика и интерпретация языка разделены, что упрощает понимание и изменение.

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

1️⃣ Ограниченная производительность: Может быть неэффективным для сложных или очень больших грамматик.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Посредник (Mediator): Интерфейс, определяющий методы для взаимодействия с коллегами.

Конкретный посредник (ConcreteMediator): Реализует методы взаимодействия, определённые в интерфейсе посредника.

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

from abc import ABC, abstractmethod

# Посредник
class Mediator(ABC):
@abstractmethod
def notify(self, sender, event):
pass

# Конкретный посредник
class ConcreteMediator(Mediator):
def __init__(self):
self.button = None
self.textbox = None

def set_button(self, button):
self.button = button

def set_textbox(self, textbox):
self.textbox = textbox

def notify(self, sender, event):
if event == "button_clicked":
self.textbox.enable()
elif event == "textbox_filled":
self.button.enable()

# Коллеги
class Button:
def __init__(self, mediator):
self.mediator = mediator
self.enabled = False

def click(self):
print("Button clicked.")
self.mediator.notify(self, "button_clicked")

def enable(self):
self.enabled = True
print("Button enabled.")

class TextBox:
def __init__(self, mediator):
self.mediator = mediator
self.enabled = False

def fill(self):
print("TextBox filled.")
self.mediator.notify(self, "textbox_filled")

def enable(self):
self.enabled = True
print("TextBox enabled.")

# Клиентский код
mediator = ConcreteMediator()
button = Button(mediator)
textbox = TextBox(mediator)

mediator.set_button(button)
mediator.set_textbox(textbox)

button.click() # Button clicked. TextBox enabled.
textbox.fill() # TextBox filled. Button enabled.


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

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

2️⃣ Упрощение взаимодействий: Все взаимодействия централизованы, что упрощает управление ими.

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

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

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

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

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

Когда нужно уменьшить связность между множеством взаимодействующих объектов.

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

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

Паттерн "Посредник" является мощным инструментом для управления взаимодействиями в системе, улучшая её модульность и уменьшая сложность.

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

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

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

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

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

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

2️⃣ Сохранение состояния: Позволяет сохранять состояния объектов в определённые моменты времени.

3️⃣ Инкапсуляция состояния: Хранит внутреннее состояние объекта, не нарушая его инкапсуляции.

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

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

Хранитель (Memento): Объект, который сохраняет состояние другого объекта.

Создатель (Originator): Объект, чьё состояние сохраняется и восстанавливается.

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

# Хранитель
class Memento:
def __init__(self, state):
self._state = state

def get_state(self):
return self._state

# Создатель
class TextEditor:
def __init__(self):
self._state = ""

def type(self, text):
self._state += text

def save(self):
return Memento(self._state)

def restore(self, memento):
self._state = memento.get_state()

def get_state(self):
return self._state

# Опекун
class History:
def __init__(self):
self._mementos = []

def save(self, memento):
self._mementos.append(memento)

def undo(self):
if not self._mementos:
return None
return self._mementos.pop()

# Клиентский код
editor = TextEditor()
history = History()

# Пользователь вводит текст
editor.type("Hello, ")
editor.type("world!")
print(editor.get_state()) # Hello, world!

# Сохранение состояния
history.save(editor.save())

# Продолжение ввода текста
editor.type(" How are you?")
print(editor.get_state()) # Hello, world! How are you?

# Восстановление состояния
editor.restore(history.undo())
print(editor.get_state()) # Hello, world!


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

1️⃣ Отмена и восстановление: Легко реализовать функции отмены и восстановления.

2️⃣ Инкапсуляция состояния: Состояние сохраняется и восстанавливается без нарушения инкапсуляции.

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

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

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

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

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

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

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

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

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
📌 Что такое Наблюдатель (Observer) ?

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

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

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

1️⃣ Обновление состояния: Автоматически оповещает зависимые объекты о изменениях в объекте-наблюдаемом.

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

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

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

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

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

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

Наблюдатель (Observer): Интерфейс или абстрактный класс, определяющий метод для обновления состояния в ответ на оповещения.

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

from abc import ABC, abstractmethod

# Интерфейс наблюдателя
class Observer(ABC):
@abstractmethod
def update(self, temperature):
pass

# Конкретный наблюдатель
class TemperatureDisplay(Observer):
def update(self, temperature):
print(f"Temperature Display: Temperature updated to {temperature}°C")

class TemperatureAlert(Observer):
def update(self, temperature):
if temperature > 30:
print("Temperature Alert: Temperature is too high!")

# Субъект
class WeatherStation:
def __init__(self):
self._observers = []
self._temperature = None

def add_observer(self, observer):
self._observers.append(observer)

def remove_observer(self, observer):
self._observers.remove(observer)

def set_temperature(self, temperature):
self._temperature = temperature
self.notify_observers()

def notify_observers(self):
for observer in self._observers:
observer.update(self._temperature)

# Клиентский код
weather_station = WeatherStation()
display = TemperatureDisplay()
alert = TemperatureAlert()

weather_station.add_observer(display)
weather_station.add_observer(alert)

weather_station.set_temperature(25) # Temperature Display: Temperature updated to 25°C
weather_station.set_temperature(35) # Temperature Display: Temperature updated to 35°C
# Temperature Alert: Temperature is too high!


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

1️⃣ Автоматическое оповещение: Автоматически обновляет наблюдателей при изменении состояния субъекта.

2️⃣ Разделение обязанностей: Субъект не знает о конкретных наблюдателях и их логике.

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

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

1️⃣ Порядок уведомления: Порядок оповещения наблюдателей может быть важен и требует управления.

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

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

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

Когда необходимо централизованное оповещение об изменениях состояния.

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

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

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

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

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

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

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

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

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

3️⃣ Изменение поведения во время выполнения: Объект может динамически изменять своё поведение в зависимости от текущего состояния.

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

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

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

Состояние (State): Интерфейс или абстрактный класс, определяющий общие методы для всех конкретных состояний.

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

from abc import ABC, abstractmethod

# Интерфейс состояния
class State(ABC):
@abstractmethod
def insert_coin(self, context):
pass

@abstractmethod
def press_button(self, context):
pass

@abstractmethod
def dispense(self, context):
pass

# Конкретные состояния
class NoCoinState(State):
def insert_coin(self, context):
print("Coin inserted.")
context.state = context.has_coin_state

def press_button(self, context):
print("Insert coin first.")

def dispense(self, context):
print("Insert coin first.")

class HasCoinState(State):
def insert_coin(self, context):
print("Coin already inserted.")

def press_button(self, context):
print("Button pressed.")
context.state = context.sold_state

def dispense(self, context):
print("Press button to dispense.")

class SoldState(State):
def insert_coin(self, context):
print("Wait! Dispensing in progress.")

def press_button(self, context):
print("Wait! Dispensing in progress.")

def dispense(self, context):
print("Ticket dispensed.")
context.state = context.no_coin_state

# Контекст
class TicketMachine:
def __init__(self):
self.no_coin_state = NoCoinState()
self.has_coin_state = HasCoinState()
self.sold_state = SoldState()
self.state = self.no_coin_state

def insert_coin(self):
self.state.insert_coin(self)

def press_button(self):
self.state.press_button(self)

def dispense(self):
self.state.dispense(self)

# Клиентский код
machine = TicketMachine()

machine.insert_coin() # Coin inserted.
machine.press_button() # Button pressed.
machine.dispense() # Ticket dispensed.

machine.press_button() # Insert coin first.
machine.insert_coin() # Coin inserted.
machine.dispense() # Press button to dispense.
machine.press_button() # Button pressed.
machine.dispense() # Ticket dispensed.


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

1️⃣ Управление состояниями: Упрощает управление сложными состояниями объекта.

2️⃣ Изолирование состояний: Позволяет разделить код, относящийся к разным состояниям.

3️⃣ Динамическое изменение поведения: Объект может динамически изменять своё поведение.

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

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

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

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

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

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍1👀1
📌 Что такое паттерн Стратегия (Strategy) ?

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

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

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

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

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

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

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

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

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

Конкретные стратегии (ConcreteStrategy): Реализации различных алгоритмов, которые реализуют интерфейс стратегии.

Контекст (Context): Класс, использующий стратегию для выполнения задачи.

from abc import ABC, abstractmethod

# Интерфейс стратегии
class Strategy(ABC):
@abstractmethod
def sort(self, data):
pass

# Конкретные стратегии
class BubbleSortStrategy(Strategy):
def sort(self, data):
print("Sorting using Bubble Sort")
for i in range(len(data)):
for j in range(0, len(data)-i-1):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]

class QuickSortStrategy(Strategy):
def sort(self, data):
print("Sorting using Quick Sort")
self.quick_sort(data, 0, len(data) - 1)

def quick_sort(self, data, low, high):
if low < high:
pi = self.partition(data, low, high)
self.quick_sort(data, low, pi - 1)
self.quick_sort(data, pi + 1, high)

def partition(self, data, low, high):
pivot = data[high]
i = low - 1
for j in range(low, high):
if data[j] <= pivot:
i = i + 1
data[i], data[j] = data[j], data[i]
data[i + 1], data[high] = data[high], data[i + 1]
return i + 1

# Контекст
class SortingContext:
def __init__(self, strategy: Strategy):
self._strategy = strategy

def set_strategy(self, strategy: Strategy):
self._strategy = strategy

def sort(self, data):
self._strategy.sort(data)

# Клиентский код
data = [5, 2, 9, 1, 5, 6]

context = SortingContext(BubbleSortStrategy())
context.sort(data)
print(data) # [1, 2, 5, 5, 6, 9]

context.set_strategy(QuickSortStrategy())
data = [3, 7, 8, 5, 2, 1, 9, 5, 4]
context.sort(data)
print(data) # [1, 2, 3, 4, 5, 5, 7, 8, 9]


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

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

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

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

Недостатки:

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

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

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

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

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

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

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

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

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