Python | Вопросы собесов
13.9K subscribers
37 photos
1 file
928 links
Cайт: easyoffer.ru
Реклама: @easyoffer_adv
ВП: @easyoffer_vp

Тесты t.me/+20tRfhrwPpM4NDQy
Задачи t.me/+nsl4meWmhfQwNDVi
Вакансии t.me/+cXGKkrOY2-w3ZTky
Download Telegram
🤔 Что такое паттерн Адаптер (Adapter)?

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

🚩Основные концепции

Целевой интерфейс (Target Interface): Интерфейс, который ожидает клиент.
Клиент (Client): Объект, который использует целевой интерфейс для взаимодействия с другими объектами.
Адаптируемый интерфейс (Adaptee): Существующий интерфейс, который необходимо адаптировать.
Адаптер (Adapter): Класс, который оборачивает адаптируемый интерфейс и преобразует его в целевой интерфейс.

🚩Примеры

Определение целевого интерфейса и адаптируемого интерфейса
class EuropeanSocketInterface:
def voltage(self):
pass

def live(self):
pass

def neutral(self):
pass

def earth(self):
pass

class USASocket:
def voltage(self):
return 120

def live(self):
return 1

def neutral(self):
return -1


Создание адаптера
class Adapter(EuropeanSocketInterface):
def __init__(self, usa_socket):
self.usa_socket = usa_socket

def voltage(self):
return self.usa_socket.voltage()

def live(self):
return self.usa_socket.live()

def neutral(self):
return self.usa_socket.neutral()

def earth(self):
return 0 # В американских розетках может не быть заземления


Использование адаптера
def client_code(socket):
print(f"Voltage: {socket.voltage()}V")
print(f"Live: {socket.live()}")
print(f"Neutral: {socket.neutral()}")
print(f"Earth: {socket.earth()}")

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


🚩Плюсы

Совместимость: Позволяет объектам с несовместимыми интерфейсами работать вместе.
Простота интеграции: Упрощает интеграцию старого кода с новым, минимизируя изменения.
Гибкость: Позволяет изменять и расширять существующие классы без изменения их исходного кода.

🚩Минусы

Сложность: Может добавить дополнительный уровень абстракции, что может усложнить систему.
Зависимость: Адаптер может зависеть от конкретных деталей реализации адаптируемого интерфейса.

🚩Разновидности паттерна "Адаптер"

Объектный адаптер: Использует композицию для оборачивания объекта.
Классовый адаптер: Использует множественное наследование для адаптации одного интерфейса к другому.

Пример классового адаптера:
class USASocket:
def voltage(self):
return 120

def live(self):
return 1

def neutral(self):
return -1

class EuropeanSocketInterface:
def voltage(self):
pass

def live(self):
pass

def neutral(self):
pass

def earth(self):
pass

class Adapter(EuropeanSocketInterface, USASocket):
def earth(self):
return 0 # В американских розетках может не быть заземления

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


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍74
🤔 Что такое паттерн Заместитель (Proxy)?

Это структурный шаблон проектирования, который предоставляет объект, управляющий доступом к другому объекту. Этот паттерн создаёт суррогат или заместителя для другого объекта и контролирует доступ к нему.

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

🟠Управление доступом
Когда необходимо контролировать доступ к ресурсу.
🟠Отложенная инициализация
Когда необходимо отложить создание ресурсоёмких объектов до момента их первого использования.
🟠Управление ресурсами
Для управления ресурсами, такими как память или сетевые соединения.
🟠Логирование и кэширование
Для добавления дополнительной функциональности, такой как логирование или кэширование, без изменения кода основного объекта.

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

🟠Управляющий заместитель (Virtual Proxy):
Контролирует доступ к объекту, создавая его по требованию.
🟠Защитный заместитель (Protection Proxy):
Контролирует доступ к объекту, ограничивая права пользователей.
🟠Удалённый заместитель (Remote Proxy)
Управляет доступом к объекту, находящемуся в другом адресном пространстве.
🟠Кэш-прокси (Cache Proxy)
Кэширует результаты запросов к объекту для повышения производительности.

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

Заместитель реализует интерфейс основного объекта и перенаправляет вызовы к реальному объекту, добавляя при этом дополнительную функциональность. В этом примере класс Proxy контролирует доступ к классу RealSubject, добавляя проверку доступа и логирование.
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()


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍71
🤔 Что такое поведенческие паттерны?

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

🚩Зачем нужны поведенческие паттерны?

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

🚩 Примеры поведенческих паттернов

Стратегия (Strategy)
Позволяет выбирать алгоритм на основе контекста, без изменения класса, который его использует.
from abc import ABC, abstractmethod

class Strategy(ABC):
@abstractmethod
def execute(self, data):
pass

class ConcreteStrategyA(Strategy):
def execute(self, data):
return sorted(data)

class ConcreteStrategyB(Strategy):
def execute(self, data):
return sorted(data, reverse=True)

class Context:
def __init__(self, strategy: Strategy):
self._strategy = strategy

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

def execute_strategy(self, data):
return self._strategy.execute(data)

data = [5, 2, 9, 1]
context = Context(ConcreteStrategyA())
print(context.execute_strategy(data)) # [1, 2, 5, 9]

context.set_strategy(ConcreteStrategyB())
print(context.execute_strategy(data)) # [9, 5, 2, 1]


Наблюдатель (Observer)
Определяет зависимость "один ко многим" между объектами таким образом, что при изменении состояния одного объекта все зависимые объекты оповещаются и обновляются автоматически.
class Subject:
def __init__(self):
self._observers = []

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

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

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

class Observer:
def update(self, message):
pass

class ConcreteObserver(Observer):
def update(self, message):
print(f"Observer received: {message}")

subject = Subject()
observer1 = ConcreteObserver()
observer2 = ConcreteObserver()

subject.add_observer(observer1)
subject.add_observer(observer2)

subject.notify_observers("Hello Observers!") # Observer received: Hello Observers!


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 Что такое Цепочка ответственности (Chain of responsobility)?

Цепочка ответственности (Chain of Responsibility) — это поведенческий паттерн проектирования, который позволяет передавать запрос по цепочке потенциальных обработчиков, пока один из них не обработает запрос. Этот паттерн избавляет отправителя запроса от необходимости знать, какой объект в цепочке обработает его запрос.

🚩Зачем нужен паттерн Цепочка ответственности?

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

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

Рассмотрим пример, где запросы обрабатываются различными уровнями поддержки (например, базовая, средняя и расширенная поддержка).
from abc import ABC, abstractmethod

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

@abstractmethod
def handle(self, request):
if self._successor:
return self._successor.handle(request)
return None

class BasicSupportHandler(Handler):
def handle(self, request):
if request == 'basic':
return "Basic support handled the request"
return super().handle(request)

class IntermediateSupportHandler(Handler):
def handle(self, request):
if request == 'intermediate':
return "Intermediate support handled the request"
return super().handle(request)

class AdvancedSupportHandler(Handler):
def handle(self, request):
if request == 'advanced':
return "Advanced support handled the request"
return super().handle(request)

# Создаем цепочку обработчиков
handler_chain = BasicSupportHandler(
IntermediateSupportHandler(
AdvancedSupportHandler()
)
)

# Тестируем цепочку
print(handler_chain.handle('basic')) # Basic support handled the request
print(handler_chain.handle('intermediate')) # Intermediate support handled the request
print(handler_chain.handle('advanced')) # Advanced support handled the request
print(handler_chain.handle('unknown')) # None (запрос не обработан)


🚩Как это работает

🟠Создание абстрактного класса `Handler`:
Все конкретные обработчики наследуются от него и реализуют метод handle.
🟠Реализация конкретных обработчиков:
Каждый обработчик проверяет, может ли он обработать запрос. Если может, он обрабатывает его и возвращает результат. Если не может, он передает запрос следующему обработчику в цепочке.
🟠Создание цепочки обработчиков:
Обработчики связываются друг с другом, образуя цепочку.
🟠Передача запроса: Запрос передается по цепочке, пока один из обработчиков не обработает его или пока не будет достигнут конец цепочки.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍101
🤔 Что такое паттерн Команда (Command)?

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

🚩Зачем нужен паттерн Команда?

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

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

Рассмотрим пример реализации паттерна Команда для управления светом (включение и выключение).
from abc import ABC, abstractmethod

# Интерфейс команды
class Command(ABC):
@abstractmethod
def execute(self):
pass

@abstractmethod
def undo(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: Light):
self._light = light

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

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

# Конкретная команда для выключения света
class LightOffCommand(Command):
def __init__(self, light: Light):
self._light = light

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

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

# Инициатор команды
class RemoteControl:
def __init__(self):
self._command = None

def set_command(self, command: Command):
self._command = command

def press_button(self):
if self._command:
self._command.execute()

def press_undo(self):
if self._command:
self._command.undo()

# Использование паттерна Команда
light = Light()
light_on_command = LightOnCommand(light)
light_off_command = LightOffCommand(light)

remote = RemoteControl()

# Включаем свет
remote.set_command(light_on_command)
remote.press_button() # Light is ON
remote.press_undo() # Light is OFF

# Выключаем свет
remote.set_command(light_off_command)
remote.press_button() # Light is OFF
remote.press_undo() # Light is ON


🚩Как это работает

🟠Интерфейс `Command`:
Объявляет методы execute и undo, которые должны реализовать конкретные команды.
🟠Конкретные команды:
Реализуют интерфейс Command и определяют, как выполнять и отменять действия.
🟠Получатель (`Light`):
Объект, который выполняет действия (в данном случае, включение и выключение света).
🟠Инициатор (`RemoteControl`):
Объект, который вызывает команды. Он не знает, что именно делает команда, а просто вызывает её методы execute и undo.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
🤔 Что такое паттерн Интерпретатор (Interpreter)?

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

🚩Зачем нужен?

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

🚩Пример

from abc import ABC, abstractmethod

# Интерфейс выражения
class Expression(ABC):
@abstractmethod
def interpret(self):
pass

# Конкретное выражение для чисел
class Number(Expression):
def __init__(self, value):
self.value = value

def interpret(self):
return self.value

# Конкретное выражение для сложения
class Add(Expression):
def __init__(self, left: Expression, right: Expression):
self.left = left
self.right = right

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

# Конкретное выражение для умножения
class Multiply(Expression):
def __init__(self, left: Expression, right: Expression):
self.left = left
self.right = right

def interpret(self):
return self.left.interpret() * self.right.interpret()

# Клиентский код для использования паттерна Интерпретатор
def main():
# Создаем выражение: (5 + 10) * 2
expression = Multiply(
Add(Number(5), Number(10)),
Number(2)
)

result = expression.interpret()
print(f"Result: {result}") # Result: 30

if __name__ == "__main__":
main()


1⃣Интерфейс `Expression`:
Объявляет метод interpret, который должен реализовать каждое конкретное выражение.
2⃣Конкретные выражения:
Классы Number, Add и Multiply, которые реализуют интерфейс Expression и определяют интерпретацию чисел, сложения и умножения соответственно.
3⃣Компоновка выражений:
Выражения могут быть составными, например, Add и Multiply могут принимать другие выражения в качестве аргументов.
4⃣Интерпретация:
Метод interpret вызывается для вычисления значения выражения.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81
🤔 Какие есть типы данных в Python?

В Python существует несколько встроенных типов данных: числовые типы (int, float, complex), строки (str), булевы значения (bool), списки (list), кортежи (tuple), множества (set) и словари (dict). Также есть типы для работы с бинарными данными, такие как bytes и bytearray. Кроме того, существуют пользовательские типы, которые можно создавать с помощью классов. Python поддерживает динамическую типизацию, где тип переменной определяется автоматически при присваивании значения.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍26
🤔 Что такое паттерн Мост (Bridge)?

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

🚩 Зачем нужен

🟠Разделение абстракции и реализации:
Он позволяет отделить абстракцию от ее реализации, что упрощает поддержку и расширение системы.
🟠Уменьшение количества подклассов:
Без применения этого паттерна, если у нас есть несколько вариантов абстракции и несколько вариантов реализации, то нам пришлось бы создавать классы для всех возможных комбинаций, что приводит к взрывному росту количества классов.
🟠Гибкость:
Это позволяет изменять и абстракцию, и реализацию независимо друг от друга.

🚩Как используется

🟠Абстракция (Abstraction):
Определяет интерфейс и хранит ссылку на объект Implementor.
🟠Расширенная абстракция (RefinedAbstraction):
Наследует Abstraction и расширяет интерфейс.
🟠Реализатор (Implementor):
Определяет интерфейс для всех реализаций.
🟠Конкретный реализатор (ConcreteImplementor):
Реализует интерфейс Implementor.

Допустим, у нас есть программа для управления различными типами устройств (например, телевизор и радио), которые можно включать и выключать. Мы хотим, чтобы способ управления устройствами мог изменяться независимо от типов устройств.
# Implementor
class Device:
def is_enabled(self):
pass

def enable(self):
pass

def disable(self):
pass

# ConcreteImplementor
class TV(Device):
def __init__(self):
self._on = False

def is_enabled(self):
return self._on

def enable(self):
self._on = True

def disable(self):
self._on = False

class Radio(Device):
def __init__(self):
self._on = False

def is_enabled(self):
return self._on

def enable(self):
self._on = True

def disable(self):
self._on = False

# Abstraction
class RemoteControl:
def __init__(self, device):
self._device = device

def toggle_power(self):
if self._device.is_enabled():
self._device.disable()
else:
self._device.enable()

# RefinedAbstraction
class AdvancedRemoteControl(RemoteControl):
def mute(self):
print("Device is muted.")

# Клиентский код
tv = TV()
remote = RemoteControl(tv)
remote.toggle_power() # Включает TV

radio = Radio()
advanced_remote = AdvancedRemoteControl(radio)
advanced_remote.toggle_power() # Включает Radio
advanced_remote.mute() # Заглушает Radio


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Что такое контекстный менеджер?

Контекстный менеджер в Python — это конструкция, которая управляет ресурсами и обеспечивает выполнение определенных действий до и после использования ресурса. Чаще всего используется с оператором `with`, чтобы гарантировать корректное открытие и закрытие ресурсов, таких как файлы или сетевые соединения. В классе контекстного менеджера должны быть реализованы методы `__enter__()` и `__exit__()`. Этот механизм помогает избежать ошибок, связанных с неправильным управлением ресурсами.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай
📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥92
🤔 Что такое паттерн Компоновщик (Composite)?

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

🚩Зачем нужен?

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

🚩Как используется паттерн Компоновщик?

🟠Лист (Leaf):
это базовый элемент без подкомпонентов.
🟠Компоновщик (Composite):
это элемент, который может содержать другие компоненты, включая и листья, и другие компоновщики.
from abc import ABC, abstractmethod

# Абстрактный компонент
class Graphic(ABC):
@abstractmethod
def draw(self):
pass

# Лист
class Circle(Graphic):
def draw(self):
print("Drawing a Circle")

# Компоновщик
class CompositeGraphic(Graphic):
def __init__(self):
self.graphics = []

def add(self, graphic):
self.graphics.append(graphic)

def remove(self, graphic):
self.graphics.remove(graphic)

def draw(self):
for graphic in self.graphics:
graphic.draw()

# Клиентский код
circle1 = Circle()
circle2 = Circle()
composite = CompositeGraphic()
composite.add(circle1)
composite.add(circle2)

# Рисуем все элементы
composite.draw()


🚩Плюсы

Упрощение работы с иерархиями:
Легко обрабатывать как простые, так и составные объекты.
Расширяемость:
Можно легко добавлять новые типы компонентов.
Сложность:
Могут возникнуть сложности при управлении более сложными структурами.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🤔 В чем разница между итератором и генератором?

Итератор — это объект, который поддерживает метод `__iter__()` и `__next__()` и позволяет проходить по коллекции элементов. Генератор — это специальный вид итератора, который создается с помощью ключевого слова `yield` и позволяет лениво возвращать элементы по одному, сохраняя состояние между вызовами. Генераторы обычно используются для обработки больших данных, поскольку они не требуют загрузки всего набора данных в память. Итераторы, в свою очередь, могут быть созданы вручную с помощью классов.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍101
🤔 Что такое паттерн Фасад (Facade)?

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

🚩Зачем нужен?

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

🚩Как используется?

Фасад создаётся как класс, который инкапсулирует взаимодействие с одной или несколькими подсистемами. Клиенты обращаются к этому фасаду, чтобы выполнять нужные действия, не вдаваясь в детали реализации этих действий.
# Подсистема 1
class CPU:
def freeze(self):
print("CPU freezing")

def jump(self, position):
print(f"CPU jumping to {position}")

def execute(self):
print("CPU executing")

# Подсистема 2
class Memory:
def load(self, position, data):
print(f"Memory loading {data} at {position}")

# Подсистема 3
class HardDrive:
def read(self, lba, size):
return f"Reading {size} bytes from LBA {lba}"

# Фасад
class ComputerFacade:
def __init__(self):
self.cpu = CPU()
self.memory = Memory()
self.hard_drive = HardDrive()

def start(self):
self.cpu.freeze()
self.memory.load("0x00", self.hard_drive.read("100", "1024"))
self.cpu.jump("0x00")
self.cpu.execute()

# Клиентский код
computer = ComputerFacade()
computer.start()


🚩Плюсы

Упрощение интерфейса: Снижает количество методов, с которыми нужно взаимодействовать клиенту.
Изоляция клиентов от подсистем: Клиенты не зависят от деталей реализации подсистем, что упрощает их модификацию и замену.
Снижение связности: Уменьшает зависимость между клиентами и сложными подсистемами.

🚩Минусы

Ограниченная функциональность: Может возникнуть ситуация, когда фасад не предоставляет весь необходимый функционал, требующийся клиенту.
Дополнительный слой абстракции: Создание фасада добавляет ещё один уровень абстракции, что может слегка усложнить систему.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Что такое SOLID?

SOLID — это пять принципов объектно-ориентированного программирования, которые помогают проектировать гибкие, расширяемые и поддерживаемые системы. Они включают в себя: Single Responsibility (одна ответственность), Open/Closed (открытость для расширения, закрытость для изменений), Liskov Substitution (замена по Лисков), Interface Segregation (разделение интерфейсов) и Dependency Inversion (инверсия зависимостей). Эти принципы улучшают архитектуру программного обеспечения и делают код более надежным.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍9
🤔 Что такое хранитель (Memento)?

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

🚩Зачем нужен?

🟠Сохранение состояния:
Позволяет сохранять текущее состояние объекта и восстанавливать его позже.
🟠Инкапсуляция:
Обеспечивает сохранение состояния объекта без нарушения его инкапсуляции. Внутренние детали объекта остаются скрытыми от других объектов.
🟠Отмена и повтор операций:
Поддерживает функциональность отмены и повтора операций, так как позволяет возвращать объект к предыдущим состояниям.
Пример реализации
class Memento:
def __init__(self, state: str):
self._state = state

def get_state(self) -> str:
return self._state

class TextEditor:
def __init__(self):
self._state = ""
self._history = []

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

def _save_state(self):
self._history.append(Memento(self._state))

def undo(self):
if not self._history:
return
memento = self._history.pop()
self._state = memento.get_state()

def get_content(self) -> str:
return self._state

# Клиентский код для использования паттерна Хранитель
def main():
editor = TextEditor()

editor.type("Hello, ")
editor.type("world!")
print(editor.get_content()) # Hello, world!

editor.undo()
print(editor.get_content()) # Hello,

editor.undo()
print(editor.get_content()) #

if __name__ == "__main__":
main()


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

2⃣`TextEditor`:
Создает и использует объекты Memento для сохранения и восстановления своего состояния. Методы type и undo позволяют редактировать текст и отменять изменения.

3⃣`_save_state`:
Сохраняет текущее состояние редактора в истории перед каждым изменением.

4⃣`undo`:
Восстанавливает предыдущее состояние редактора из истории.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31