Паттерн Singleton
Часть раздела Object Oriented Programming путешествия по Python на Coddy — урок 45 из 64.
Паттерн Singleton гарантирует, что class имеет только один instance и предоставляет глобальную точку access к нему. Это полезно для таких ресурсов, как подключения к database или settings конфигурации.
Вот базовая реализация паттерна Singleton:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instanceМетод __new__ управляет созданием объектов. Он проверяет, существует ли уже instance, перед созданием нового.
Создайте два экземпляра класса Singleton:
singleton1 = Singleton()
singleton2 = Singleton()Проверьте, ссылаются ли обе переменные на один и тот же объект:
print(singleton1 is singleton2) # True
print(id(singleton1)) # Тот же адрес памяти
print(id(singleton2)) # Тот же адрес памятиВот более практический пример с подключением к базе данных:
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection = "Connected to MySQL database"
print("Creating new database connection")
return cls._instance
def query(self, sql):
return f"Executing: {sql}"
# Первый доступ создаёт соединение
db1 = DatabaseConnection()
print(db1.connection)
# Второй доступ повторно использует то же соединение
db2 = DatabaseConnection()
print(db2.connection)
print(db1.query("SELECT * FROM users"))
print(db1 is db2)Создайте менеджер конфигурации с использованием шаблона Singleton:
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.settings = {}
return cls._instance
def set_setting(self, key, value):
self.settings[key] = value
def get_setting(self, key):
return self.settings.get(key)
config1 = Config()
config1.set_setting("debug", True)
config2 = Config()
print(config2.get_setting("debug")) # True - те же настройкиВывод:
True
140234567890123
140234567890123
Creating new database connection
Connected to MySQL database
Connected to MySQL database
Executing: SELECT * FROM users
True
TrueКлючевой момент: Паттерн Singleton использует __new__ для управления созданием object, гарантируя, что существует only one instance. Используйте его для ресурсов, которые должны have only one копию во всем приложении, таких как database connection, логгеры или менеджеры конфигурации. Помните, что все переменные, указывающие на Singleton, ссылаются на same object в memory.
Задание
ЛегкоВ этом задании вам предстоит реализовать паттерн проектирования Singleton для класса подключения к базе данных.
- Отредактируйте файл
databaseconnection.py, чтобы реализовать паттерн Singleton в соответствии с комментариями TODO - Файл
driver.pyсодержит развернутые тестовые сценарии и не должен изменяться
Попробуйте сами
from databaseconnection import DatabaseConnection
# Комплексный обработчик тестовых случаев
test_case = input()
if test_case == "identity_check":
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # Должно вывести True
elif test_case == "connect_state":
db = DatabaseConnection()
print(f"Initial connected state: {db.connected}") # Должно вывести False
db.connect()
print(f"After connect: {db.connected}") # Должно вывести True
elif test_case == "disconnect_state":
db = DatabaseConnection()
db.connect()
db.disconnect()
print(f"After disconnect: {db.connected}") # Должно вывести False
elif test_case == "multiple_instances_same_state":
db1 = DatabaseConnection()
db1.connect()
db2 = DatabaseConnection()
print(f"db2 connected state: {db2.connected}") # Должно вывести True
elif test_case == "host_value":
db = DatabaseConnection()
print(f"Default host: {db.host}") # Должно вывести "localhost"
db.host = "new-server"
db2 = DatabaseConnection()
print(f"New instance host: {db2.host}") # Должно вывести "new-server"
elif test_case == "init_once":
db1 = DatabaseConnection()
db1.host = "custom-host"
db2 = DatabaseConnection()
print(f"Both instances have same host: {db1.host == db2.host}") # Должно вывести True
print(f"Host value: {db1.host}") # Должно вывести "custom-host"
elif test_case == "connect_message":
db = DatabaseConnection()
db.connect() # Should print "Connected to database at localhost"
elif test_case == "disconnect_message":
db = DatabaseConnection()
db.connect()
db.disconnect() # Should print "Disconnected from database"
elif test_case == "attribute_modification":
db1 = DatabaseConnection()
db1.port = 3306
db2 = DatabaseConnection()
print(f"db2 has port attribute: {hasattr(db2, 'port')}") # Должно вывести True
print(f"db2 port value: {db2.port}") # Должно вывести 3306
elif test_case == "reset_connection":
db1 = DatabaseConnection()
db1.connect()
print(f"Connected state: {db1.connected}") # Должно вывести True
db2 = DatabaseConnection()
print(f"New instance connected state: {db2.connected}") # Должно вывести True
db2.disconnect()
db3 = DatabaseConnection()
print(f"After disconnect, new instance state: {db3.connected}") # Должно вывести False
elif test_case == "multiple_connects":
db = DatabaseConnection()
db.connect()
db.connect()
db.connect()
print(f"Connected state after multiple connects: {db.connected}") # Должно вывести True
db.disconnect()
print(f"Connected state after disconnect: {db.connected}") # Должно вывести False
elif test_case == "host_change_affects_message":
db = DatabaseConnection()
db.host = "custom-server"
db.connect() # Will still print "Connected to database at localhost"
# Метод connect имеет жёстко заданное сообщение, которое не использует атрибут host
print("Message still shows localhost: True")В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыПараметр selfМетодыАтрибутыМетод-конструктор (__init__)Повторение — Простой калькулятор4Наследование
Базовое наследованиеФункция super()Переопределение методовМножественное наследованиеПорядок разрешения методовИтоги — Иерархия сотрудников7Специальные методы
Введение в магические методыПерегрузка операторовМагические методы контейнеровПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy5Полиморфизм
Снова о переопределении методовУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовИтоги — Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияМиксиныСтатические методы и методы классаДекораторы классовМенеджеры контекста11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Свойства классов
Переменные экземпляра и классаДекораторы свойствПриватные атрибутыИтоги — Менеджер банковского счета6Инкапсуляция
Public, Protected, Private члены классаМодификаторы доступаСокрытие данныхДекораторы property: продвинутый уровеньИтоги: Система учета студентов12Проект: Управление библиотекой
Обзор проектаКлассы Book и UserСистема выдачи книгФункционал поискаИнтерфейс администратораТестирование и интеграция