Наблюдатель (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
Результат:

ссылка на оригинал статьи https://habr.com/ru/articles/930094/
Добавить комментарий