Наблюдатель (observer)
Определение: паттерн наблюдатель определяет отношение «один ко многим» между объектами таким образом, что при измении состояния одного объекта происходит автоматическое оповещение и обновление всех зависимых объектов.
Простыми словами: у нас есть класс, у которого какие‑то параметры меняются со временем. Наблюдатели — объекты, которые каждый раз получают уведомление, когда у класса меняется какой‑то параметр.
Пример: рассмотрим ситуацию, когда у нас есть пациент у которого нужно отслеживать температуру и пульс и отправлять информацию на основе полученных данных. Пациент — наш класс, у которого со временем меняются параметры (температура и пульс). Наблюдатели — блоки кода, которые выводят информацию в те моменты, когда меняются параметры.
class AbstractClass:
"""
Абстрактный класс, у которого определены три функции:
add_obs - добавить наблюдателя
remove_obs - удалить наблюдателя
notify_observer - разослать уведомления наблюдателям
"""
def __init__(self):
self.__observers = []
def add_obs(self, observer):
self.__observers.append(observer)
def remove_obs(self, observer):
self.__observers.remove(observer)
def notify_observer(self, *arg):
for i in self.__observers:
i.update(self, *arg)
class AbstractObserver:
"""
Абстрактный наблюдатель от которого нужно будет наследоваться конкретным
наблюдателям и переопределять метод update, который
"""
def __init__(self):
pass
def update(self):
pass
class Patient(AbstractClass):
"""
Конкретный пациент - который в случае изменения параметров вызывает
функция notify_observer
"""
def __init__(self, name):
super().__init__()
self.name = name
self.params = {"temperature": 0.0, "heartrate": 0.0}
def set_value(self, measure_type, val):
if measure_type in self.params:
self.params[measure_type] = val
self.notify_observer()
else:
print("Такого параметра нет")
def get_value(self, measure_type):
if measure_type in self.params:
return self.params[measure_type]
else:
return None
class HeartbeatMonitor(AbstractObserver):
"""
Конкретный наблюдатель пульса - в зависимости от значения пульса
выводит результат
"""
def __init__(self):
super().__init__()
def update(self, tt):
if type(tt).__name__ == 'Patient':
hr = tt.get_value("heartrate")
if hr > 120:
print("Пульс слишком быстрый: " + str(hr))
elif hr < 35:
print("Пульс слишком медленный: " + str(hr))
else:
print("Пульс в норме: " + str(hr))
else:
pass
class Thermometer(AbstractObserver):
"""
Конкретный наблюдатель температуры - в зависимости от значения температуры
выводит результат
"""
def __init__(self):
super().__init__()
def update(self, tt):
if type(tt).__name__ == 'Patient':
temp = tt.get_value("temperature")
if temp > 37.8:
print("Слишком высокая температура: " + str(temp))
elif temp < 35.0:
print("Слишком низкая температура: " + str(temp))
else:
print("Температура в норме: " + str(temp))
else:
pass
import time
if __name__ == "__main__":
sub = Patient("Кирилл")
obs1 = Thermometer()
obs2 = HeartbeatMonitor()
for i in range(15):
time.sleep(1)
print("====== Шаг {} =======".format(i + 1))
if i == 3:
sub.add_obs(obs1) # На третью итерацию добавляем наблюдателя температуры
elif i == 5:
sub.add_obs(obs2) # На пятую итерацию добавляем наблюдателя пульса
elif i == 10:
sub.remove_obs(obs1) # На десятую итерацию убираем наблюдателя температуры
if i % 3 == 0:
sub.set_value("temperature", 35.5 + 0.5 * i)
elif i % 3 == 1:
sub.set_value("heartrate", 30 + 10 * i)
Результат:

Декоратор (decorator)
Определение: паттерн декоратор динамически наделяет объект новыми возможностями и является гибкой альтернативой субклассированию в области расширения функциональности.
Простыми словами: паттерн позволяет добавлять новый функционал нашему объекту, не изменяя код этого объекта.
Пример: декоратор, который запоминает с какими параметрами уже вызывалась конкретная функция и если такой параметр встретился, то сразу возвращает значение, не вызывая саму функцию (мемоизация).
import sys
def memoize(f):
cache = dict()
def wrapper(x):
if x not in cache:
cache[x] = f(x)
return cache[x]
return wrapper
@memoize
def fib(n):
if n <= 1:
return n
else:
return fib(n - 1) + fib(n - 2)
if __name__ == "__main__":
sys.setrecursionlimit(2000)
print(fib(750))
Результат:

Абстрактная фабрика (abstract factory)
Определение: паттерн предоставляет интерфейс создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов.
Простыми словами: позволяет отделить логику создания объектов от логики их использования. Предоставляет интерфейс создания семейств связанных или зависимых объектов, не специфицируя их конкретные классы.
Пример: создание элементов пользовательского интерфейса для разных операционных систем.
class Button:
def draw(self):
raise NotImplementedError
class Checkbox:
def draw(self):
raise NotImplementedError
class WindowsButton(Button):
def draw(self):
return "Drawing a Windows Button"
class WindowsCheckbox(Checkbox):
def draw(self):
return "Drawing a Windows Checkbox"
class MacOSButton(Button):
def draw(self):
return "Drawing a MacOS Button"
class MacOSCheckbox(Checkbox):
def draw(self):
return "Drawing a MacOS Checkbox"
class GUIFactory:
def create_button(self):
raise NotImplementedError
def create_checkbox(self):
raise NotImplementedError
class WindowsGUIFactory(GUIFactory):
def create_button(self):
return WindowsButton()
def create_checkbox(self):
return WindowsCheckbox()
class MacOSGUIFactory(GUIFactory):
def create_button(self):
return MacOSButton()
def create_checkbox(self):
return MacOSCheckbox()
def create_ui(factory):
button = factory.create_button()
checkbox = factory.create_checkbox()
return button.draw(), checkbox.draw()
if __name__ == "__main__":
windows_factory = WindowsGUIFactory()
windows_button, windows_checkbox = create_ui(windows_factory)
print(f"Windows UI: {windows_button}, {windows_checkbox}")
macos_factory = MacOSGUIFactory()
macos_button, macos_checkbox = create_ui(macos_factory)
print(f"MacOS UI: {macos_button}, {macos_checkbox}")
Результат:

Фабричный метод (factory method)
Определение: паттерн определяет интерфейс создания объекта, но позволяет субклассам выбрать класс создаваемого экземпляра. Таким образом, фабричный метод делегирует операцию создания экземпляра субклассам.
Простыми словами: Используется для создания отдельных объектов с гибким выбором реализации тогда, когда нужно делегировать логику выбора конкретного класса для создания одиночного объекта подклассам.
Пример: создание разных типов документов.
class Document:
def __init__(self, content):
self.content = content
def render(self):
raise NotImplementedError("Subclasses must implement this method")
class PDFDocument(Document):
def render(self):
return f"Rendering PDF Document: {self.content}"
class HTMLDocument(Document):
def render(self):
return f"Rendering HTML Document: {self.content}"
class DocumentCreator:
def create_document(self, content):
raise NotImplementedError("Subclasses must implement this method")
def display_document(self, content):
document = self.create_document(content)
print(document.render())
class PDFDocumentCreator(DocumentCreator):
def create_document(self, content):
return PDFDocument(content)
class HTMLDocumentCreator(DocumentCreator):
def create_document(self, content):
return HTMLDocument(content)
if __name__ == "__main__":
pdf_creator = PDFDocumentCreator()
pdf_creator.display_document("This is a PDF document")
html_creator = HTMLDocumentCreator()
html_creator.display_document("This is an HTML document")
Результат:

Одиночка (singleton)
Определение: паттерн гарантирует, что класс имеет только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру.
Простыми словами: как бы вы не хотели, не получится создать больше одного экземпляра класса.
Пример:
class SingletonClass:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(SingletonClass, cls).__new__(cls)
return cls._instance
singleton = SingletonClass()
new_singleton = SingletonClass()
print(singleton is new_singleton)
singleton.singl_variable = "2"
print(new_singleton.singl_variable)
Результат:

Команда (command)
Определение: паттерн инкапсулирует запрос в виде объекта, делая возможной параметризацию клиентских объектов с другими запросами, организацию очереди или регистрацию запросов, а также поддержку отмены операции.
Простыми словами: позволяет отделить то, что нужно сделать, от того, как это сделать.
Пример: включение/выключение света.
from abc import ABC, abstractmethod
class Command(ABC):
@abstractmethod
def execute(self):
pass
class Light:
def turn_on(self):
print("The light is ON")
def turn_off(self):
print("The light is OFF")
class TurnOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
class TurnOffCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_off()
class RemoteControl:
def __init__(self):
self.command = None
def set_command(self, command):
self.command = command
def press_button(self):
if self.command:
self.command.execute()
if __name__ == "__main__":
light = Light()
remote = RemoteControl()
turn_on = TurnOnCommand(light)
turn_off = TurnOffCommand(light)
remote.set_command(turn_on)
remote.press_button()
remote.set_command(turn_off)
remote.press_button()
Результат:

Адаптер (adapter)
Определение: паттерн преобразует интерфейс класса к другому интерфейсу, на который рассчитан клиент. Адаптер обеспечивает совместную работу классов, невозможную в обычных условиях из-за несовместимости интерфейсов.
Простыми словами: Позволяет классам с несовместимыми интерфейсами работать вместе. Выступает в роли переводчика, преобразуя интерфейс одного класса в интерфейс, который ожидает другой класс.
Пример:
# Интерфейс, который ожидает клиент
class NotificationService:
def send_notification(self, message, recipient):
raise NotImplementedError("Subclasses must implement this method")
# Класс, который нужно адаптировать
class LegacyNotificationSystem:
def send_legacy_notification(self, user_id, text):
print(f"Legacy system: Sending notification '{text}' to user {user_id}")
# Адаптер
class NotificationAdapter(NotificationService):
def __init__(self, legacy_system):
self.legacy_system = legacy_system
def send_notification(self, message, recipient):
# Преобразуем данные в формат, понятный для LegacyNotificationSystem
self.legacy_system.send_legacy_notification(recipient, message)
class Client:
def __init__(self, notification_service):
self.notification_service = notification_service
def send_message(self, message, recipient):
self.notification_service.send_notification(message, recipient)
if __name__ == "__main__":
legacy_system = LegacyNotificationSystem()
adapter = NotificationAdapter(legacy_system)
client = Client(adapter)
client.send_message("Hello, world!", "12345")
Результат:

Фасад (facade)
Определение: паттерн предоставляет унифицированный интерфейс к группе интерфейсов подсистемы.Он определяет высокоуровневый интерфейс, упрощающий работу с подсистемой.
Простыми словами: предоставляет упрощённый интерфейс к сложной системе, скрывает сложность системы и предоставляет клиенту более удобный и простой способ взаимодействия с ней.
Пример: вместо того, чтобы пользователю по-отдельности пользоваться классам Inventory, Payment и Notification был собран один класс OrderFacade, с которым намного проще обращаться.
class Inventory:
def check_stock(self, product_id):
print(f"Checking stock for product {product_id}")
return True
def update_stock(self, product_id, quantity):
print(f"Updating stock for product {product_id} by {quantity}")
class Payment:
def process_payment(self, amount):
print(f"Processing payment of ${amount}")
return True
class Notification:
def send_confirmation(self, order_id):
print(f"Sending confirmation for order {order_id}")
class OrderFacade:
def __init__(self):
self.inventory = Inventory()
self.payment = Payment()
self.notification = Notification()
def place_order(self, product_id, quantity, amount):
if self.inventory.check_stock(product_id):
if self.payment.process_payment(amount):
self.inventory.update_stock(product_id, -quantity)
self.notification.send_confirmation(product_id)
print("Order placed successfully")
else:
print("Payment processing failed")
else:
print("Product is out of stock")
if __name__ == "__main__":
facade = OrderFacade()
facade.place_order(product_id=1, quantity=1, amount=100)
Результат:

Шаблонный метод (template method)
Определение: паттерн задаёт скелет алгоритма в методе, оставляя определение реализации некоторых шагов субклассам. Субклассы могут переопределять некоторые части алгоритма без изменения его структуры.
Простыми словами: создаём абстрактный класс, в котором определяем основные шаги алгоритма, например, порядок выполнения функций. При этом позволяя подклассам переопределять эти функции, не меняя его структуру.
Пример:
class ReportGenerator:
def generate_report(self):
self.collect_data()
self.format_data()
self.generate_header()
self.generate_body()
self.generate_footer()
self.output_report()
def collect_data(self):
raise NotImplementedError("Subclasses must implement this method")
def format_data(self):
raise NotImplementedError("Subclasses must implement this method")
def generate_header(self):
print("Generating default header")
def generate_footer(self):
print("Generating default footer")
def output_report(self):
print("Outputting report to console")
class SalesReportGenerator(ReportGenerator): # ConcreteClass
def collect_data(self):
print("Collecting sales data")
self.sales_data = ["Sales 1", "Sales 2", "Sales 3"]
def format_data(self):
print("Formatting sales data")
self.formatted_sales_data = "\n".join(self.sales_data)
def generate_header(self):
print("Generating Sales Report Header")
def generate_body(self):
print("Generating Sales Report Body")
print(self.formatted_sales_data)
class PerformanceReportGenerator(ReportGenerator): # ConcreteClass
def collect_data(self):
print("Collecting performance data")
self.performance_data = ["Perf 1", "Perf 2", "Perf 3"]
def format_data(self):
print("Formatting performance data for web output")
self.formatted_performance_data = "<br>".join(self.performance_data)
def generate_body(self):
print("Generating Performance Report Body")
print(self.formatted_performance_data)
def output_report(self):
print("Outputting report to web page")
if __name__ == "__main__":
sales_report = SalesReportGenerator()
sales_report.generate_report()
performance_report = PerformanceReportGenerator()
performance_report.generate_report()
Результат:

Итератор (iterator)
Определение: паттерн предоставляет механизм последовательного перебора элементов коллекции без раскрытия её внутреннего представления.
Простыми словами: используется для того, чтобы последовательно перебирать элементы коллекции не зная как они хранятся в памяти.
Пример:
class NumberIterator:
def __init__(self, numbers):
self._numbers = numbers
self._index = 0
def __iter__(self):
return self
def __next__(self):
if self._index < len(self._numbers):
result = self._numbers[self._index]
self._index += 1
return result
else:
raise StopIteration
numbers = [1, 2, 3, 4, 5]
iterator = NumberIterator(numbers)
for number in iterator:
print(number)
Результат:

Компоновщик (composite)
Определение: паттерн объединяет объекты в древовидные структуры для представления иерархий «часть/целое». Позволяет клиенту выполнять однородные операции с отдельными объектами и их совокупностями.
Простыми словами: позволяет объединять объекты в древовидные структуры и работать с ними как с единым целым, так и по‑отдельности.
Пример: файловая система.
from abc import ABC, abstractmethod
class FileSystem(ABC):
@abstractmethod
def print(self, indent: int = 0) -> None:
pass
class File(FileSystem):
def __init__(self, name: str, size: int):
self.name = name
self.size = size
def print(self, indent: int = 0) -> None:
print(" " * indent + f"Файл: {self.name} (Размер: {self.size} KB)")
class Directory(FileSystem):
def __init__(self, name: str):
self.name = name
self.contents: list = []
def print(self, indent: int = 0) -> None:
print(" " * indent + f"Папка: {self.name}")
for entity in self.contents:
entity.print(indent + 2)
def add_entity(self, entity: FileSystem) -> None:
self.contents.append(entity)
def remove_entity(self, entity: FileSystem) -> None:
if entity in self.contents:
self.contents.remove(entity)
def main():
file1 = File("file1.txt", 128)
file2 = File("file2.txt", 1024)
file3 = File("file3.txt", 2048)
dir1 = Directory("dir1")
dir1.add_entity(file1)
dir1.add_entity(file2)
nested_dir = Directory("nested_dir")
nested_dir.add_entity(file3)
dir1.add_entity(nested_dir)
root_dir = Directory("root")
root_dir.add_entity(dir1)
root_dir.add_entity(File("root_file.txt", 256))
root_dir.print()
if __name__ == "__main__":
main()
Результат:

Состояние (state)
Определение: паттерн управляет изменением поведения объекта при изменении его внутреннего состояния. Внешне это выглядит так, словно объект меняет свой класс.
Простыми словами: паттерн реализует структуру, в которой при изменении какого-то параметра объекта меняется то, как он будет обрабатывать поступающие в него запросы.
Пример: работа лифта у которого есть два состояния: первый этаж, второй этаж.
from __future__ import annotations
from abc import ABC, abstractmethod
class Elevator:
_state = None
def __init__(self, state: State) -> None:
self.setElevator(state)
def setElevator(self, state: State):
self._state = state
self._state.elevator = self
def presentState(self):
print(f"Лифт на {type(self._state).__name__}")
def pushDownBtn(self):
self._state.pushDownBtn()
def pushUpBtn(self):
self._state.pushUpBtn()
class State(ABC):
def __init__(self):
self._elevator = None
@property
def elevator(self) -> Elevator:
return self._elevator
@elevator.setter
def elevator(self, elevator: Elevator) -> None:
self._elevator = elevator
@abstractmethod
def pushDownBtn(self) -> None:
pass
@abstractmethod
def pushUpBtn(self) -> None:
pass
class FirstFloor(State):
def pushDownBtn(self) -> None:
print("Уже на первом этаже")
def pushUpBtn(self) -> None:
print("Лифт поднимается на второй этаж")
self.elevator.setElevator(SecondFloor())
class SecondFloor(State):
def pushDownBtn(self) -> None:
print("Лифт опускается на первый этаж")
self.elevator.setElevator(FirstFloor())
def pushUpBtn(self) -> None:
print("Лифт уже на втором этаже")
if __name__ == "__main__":
myElevator = Elevator(FirstFloor())
myElevator.presentState()
myElevator.pushUpBtn()
myElevator.presentState()
myElevator.pushDownBtn()
myElevator.presentState()
Результат:

Заместитель (proxy)
Определение: паттерн предоставляет суррогатный объект, управляющий доступом к другому объекту.
Простыми словами: заместитель позволяет управлять доступом к объекту не изменяя сам объект.
Пример: отложенная загрузка изображения.
class Image:
def __init__(self, filename):
self.filename = filename
self.image = None # Изображение еще не загружено
def display(self):
raise NotImplementedError
class RealImage(Image):
def __init__(self, filename):
super().__init__(filename)
self.load_from_disk() # Загрузка сразу при создании
def load_from_disk(self):
print(f"Загружаю {self.filename} с диска...")
self.image = f"информация о {self.filename}"
print(f"Картинка {self.filename} загружена.")
def display(self):
print(f"Отображена {self.image}")
class ProxyImage(Image):
def __init__(self, filename):
super().__init__(filename)
self.real_image = None # Реальное изображение еще не создано
def display(self):
if self.real_image is None:
self.real_image = RealImage(self.filename) # Загружаем только при необходимости
self.real_image.display()
if __name__ == "__main__":
image1 = ProxyImage("image1.jpg")
image2 = ProxyImage("image2.png")
print("Картинки ещё не созданы")
image1.display() # Вот тут произойдет загрузка image1
image2.display() # Вот тут произойдет загрузка image2
Результат:
