Паттерн Facade (Фасад)
Facade (Фасад) - это структурный паттерн проектирования, который предоставляет простой интерфейс к сложной системе классов, библиотеке или фреймворку. Фасад скрывает сложность внутренней системы и предоставляет клиенту только необходимый функционал.
Когда использовать Facade?
- Когда вам нужно представить простой или урезанный интерфейс к сложной подсистеме
- Когда вы хотите разложить подсистему на отдельные слои (слои абстракции)
- Когда нужно уменьшить количество зависимостей между клиентом и сложной системой
Преимущества Facade
- Изолирует клиентов от компонентов сложной подсистемы
- Уменьшает coupling (связность) между клиентским кодом и подсистемой
- Делает подсистему проще в использовании и понимании
Недостатки Facade
- Фасад может стать "божественным объектом", привязанным ко всем классам программы
Пример 1: Упрощение работы с мультимедийной системой
# Сложные подсистемы
class VideoFile:
def __init__(self, filename):
self.filename = filename
class CodecFactory:
@staticmethod
def extract(file):
print(f"Extracting codec from {file.filename}")
return "codec"
class BitrateReader:
@staticmethod
def read(file, codec):
print(f"Reading file {file.filename} with {codec}")
return "buffer"
class AudioMixer:
@staticmethod
def fix(buffer):
print("Fixing audio")
return "fixed_audio"
# Фасад
class VideoConverter:
def convert(self, filename, format):
print("VideoConversionFacade: conversion started.")
file = VideoFile(filename)
codec = CodecFactory.extract(file)
buffer = BitrateReader.read(file, codec)
if format == "mp4":
print("Converting to MP4 format")
else:
print("Converting to OGG format")
result = AudioMixer.fix(buffer)
print("VideoConversionFacade: conversion completed.")
return result
# Клиентский код
if __name__ == "__main__":
converter = VideoConverter()
mp4 = converter.convert("youtubevideo.ogg", "mp4")
Пример 2: Упрощение работы с компьютером
# Сложные подсистемы
class CPU:
def execute(self):
print("CPU: Executing instructions")
def halt(self):
print("CPU: Halting")
class Memory:
def load(self, position, data):
print(f"Memory: Loading data '{data}' at position {position}")
class HardDrive:
def read(self, lba, size):
print(f"HardDrive: Reading sector {lba} with size {size}")
return "boot_data"
# Фасад
class Computer:
def __init__(self):
self.cpu = CPU()
self.memory = Memory()
self.hard_drive = HardDrive()
def start(self):
print("Computer: Starting...")
boot_data = self.hard_drive.read(0, 1024)
self.memory.load(0, boot_data)
self.cpu.execute()
print("Computer: Started successfully")
def shutdown(self):
print("Computer: Shutting down...")
self.cpu.halt()
print("Computer: Shutdown complete")
# Клиентский код
if __name__ == "__main__":
computer = Computer()
computer.start()
print("\nUsing computer...\n")
computer.shutdown()
Пример 3: Упрощение работы с банковской системой
# Сложные подсистемы
class AccountManager:
def check_account(self, account_id):
print(f"Checking account {account_id} exists")
return True
class BalanceChecker:
def get_balance(self, account_id):
print(f"Getting balance for account {account_id}")
return 1000.0
class TransactionProcessor:
def deposit(self, account_id, amount):
print(f"Depositing {amount} to account {account_id}")
def withdraw(self, account_id, amount):
print(f"Withdrawing {amount} from account {account_id}")
class SecurityManager:
def verify_pin(self, account_id, pin):
print(f"Verifying PIN for account {account_id}")
return pin == "1234"
# Фасад
class BankFacade:
def __init__(self):
self.account_manager = AccountManager()
self.balance_checker = BalanceChecker()
self.transaction_processor = TransactionProcessor()
self.security_manager = SecurityManager()
def deposit_money(self, account_id, pin, amount):
if not self.security_manager.verify_pin(account_id, pin):
print("Invalid PIN")
return False
if not self.account_manager.check_account(account_id):
print("Account not found")
return False
self.transaction_processor.deposit(account_id, amount)
print(f"Successfully deposited {amount} to account {account_id}")
return True
def withdraw_money(self, account_id, pin, amount):
if not self.security_manager.verify_pin(account_id, pin):
print("Invalid PIN")
return False
if not self.account_manager.check_account(account_id):
print("Account not found")
return False
balance = self.balance_checker.get_balance(account_id)
if balance < amount:
print("Insufficient funds")
return False
self.transaction_processor.withdraw(account_id, amount)
print(f"Successfully withdrew {amount} from account {account_id}")
return True
# Клиентский код
if __name__ == "__main__":
bank = BankFacade()
# Успешное снятие денег
bank.withdraw_money("acc123", "1234", 500)
print("\n")
# Неудачная попытка (неправильный PIN)
bank.deposit_money("acc123", "1111", 200)
Заключение
Паттерн Facade полезен, когда вам нужно:
- Предоставить простой интерфейс к сложной системе
- Уменьшить зависимости между клиентским кодом и подсистемой
- Организовать подсистему в слои
Фасад не запрещает прямой доступ к классам подсистемы, если это необходимо, но предоставляет удобный способ работы для большинства клиентов.