Паттерны проектирования – это проверенные временем решения часто встречающихся проблем в объектно-ориентированном программировании. Они представляют собой своего рода шаблоны, которые можно адаптировать под конкретные задачи. Знание паттернов позволяет писать более чистый, поддерживаемый и расширяемый код. В этой статье мы рассмотрим три популярных паттерна: Singleton (Одиночка), Factory (Фабрика) и Observer (Наблюдатель), с примерами реализации на Python.
1. Singleton (Одиночка)
Паттерн Singleton гарантирует, что у класса будет только один экземпляр, и предоставляет глобальную точку доступа к нему. Это полезно, когда требуется контролировать доступ к общему ресурсу, например, к базе данных или файлу конфигурации.
Пример на Python:
class Singleton: __instance = None
def __init__(self): if Singleton.__instance is not None:
raise Exception("Singleton cannot be instantiated more than once!")
else:
Singleton.__instance = self
@staticmethod
def get_instance():
if Singleton.__instance is None:
Singleton()
return Singleton.__instance
# Пример использования s1 = Singleton.get_instance()
s2 = Singleton.get_instance()
print(s1 is s2) # Выведет True
# Попытка создать экземпляр напрямую вызовет исключение # s3 = Singleton() # Вызовет Exception
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
class Database(metaclass=SingletonMeta):
def __init__(self, database_name): self.name = database_name
db1 = Database("mydatabase")
db2 = Database("anotherdatabase")
print(db1.name) # mydatabase print(db2.name) # mydatabase print(db1 is db2) # True
В этом примере get_instance() – статический метод, который возвращает единственный экземпляр класса. Если экземпляр еще не создан, он создается. Важно отметить, что попытка создать экземпляр напрямую через конструктор вызовет исключение. Второй пример показывает реализацию через метакласс, которая позволяет более гибко использовать паттерн.
2. Factory (Фабрика)
Паттерн Factory предоставляет интерфейс для создания объектов, но позволяет подклассам решать, какой класс инстанцировать. Это позволяет избежать жесткой привязки к конкретным классам и делает код более гибким и расширяемым. Существует несколько разновидностей этого паттерна: Simple Factory, Factory Method и Abstract Factory. Рассмотрим Simple Factory и Factory Method.
Simple Factory (Простая фабрика):
class Car: def __init__(self, model): self.model = model
def drive(self): print(f"Driving a {self.model}")
class Truck: def __init__(self, model): self.model = model
def load(self): print(f"Loading cargo in a {self.model}")
class VehicleFactory: def create_vehicle(self, type, model): if type == "car":
return Car(model)
elif type == "truck":
return Truck(model)
else:
return None
factory = VehicleFactory()
car = factory.create_vehicle("car", "Tesla")
truck = factory.create_vehicle("truck", "Volvo")
car.drive() # Driving a Tesla truck.load() # Loading cargo in a Volvo
Factory Method (Фабричный метод):
from abc import ABC, abstractmethod
class Transport(ABC):
@abstractmethod
def deliver(self):
pass
class Truck(Transport):
def deliver(self): print("Delivering by truck")
class Ship(Transport): def deliver(self): print("Delivering by ship")
class Logistics(ABC):
@abstractmethod
def create_transport(self):
pass
def plan_delivery(self):
transport = self.create_transport()
transport.deliver()
class RoadLogistics(Logistics):
def create_transport(self):
return Truck()
class SeaLogistics(Logistics):
def create_transport(self):
return Ship()
road_logistics = RoadLogistics()
sea_logistics = SeaLogistics()
road_logistics.plan_delivery() # Delivering by truck sea_logistics.plan_delivery() # Delivering by ship
Simple Factory инкапсулирует логику создания объектов в одном классе. Factory Method определяет интерфейс для создания объекта, но оставляет выбор конкретного класса за подклассами.
3. Observer (Наблюдатель)
Паттерн Observer определяет зависимость "один ко многим" между объектами. Один объект (субъект) поддерживает список своих зависимостей (наблюдателей) и автоматически уведомляет их обо всех изменениях своего состояния.
Пример на Python:
class Subject:
def __init__(self):
self._observers = []
self._state = None
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self):
for observer in self._observers:
observer.update(self._state)
@property
def state(self):
return self._state
@state.setter
def state(self, value):
self._state = value
self.notify()
class Observer:
def update(self, state): print(f"Observer received update: {state}")
subject = Subject()
observer1 = Observer()
observer2 = Observer()
subject.attach(observer1)
subject.attach(observer2)
subject.state = "Initial state" subject.state = "New state"
subject.detach(observer1)
subject.state = "Final state"
В этом примере Subject хранит список Observer и уведомляет их методом notify() при изменении своего состояния. Каждый Observer реализует метод update(), который вызывается при уведомлении.
Заключение
Паттерны проектирования – мощный инструмент для создания качественного программного обеспечения. Singleton обеспечивает единственность экземпляра класса, Factory упрощает создание объектов, а Observer позволяет реализовать механизм оповещений. Использование этих и других паттернов делает код более гибким, поддерживаемым и расширяемым. Рассмотренные примеры на Python демонстрируют практическое применение этих паттернов.