Padrão Singleton
Parte da seção Object Oriented Programming do Journey de Python da Coddy — lição 45 de 64.
O padrão Singleton garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela. Isso é útil para recursos como conexões de banco de dados ou configurações de sistema.
Aqui está uma implementação básica de Singleton:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instanceO método __new__ controla a criação de objetos. Ele verifica se uma instância já existe antes de criar uma nova.
Crie duas instâncias da classe Singleton:
singleton1 = Singleton()
singleton2 = Singleton()Verifique se ambas as variáveis referenciam o mesmo objeto:
print(singleton1 is singleton2) # True
print(id(singleton1)) # Mesmo endereço de memória
print(id(singleton2)) # Mesmo endereço de memóriaAqui está um exemplo mais prático com uma conexão de banco de dados:
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}"
# O primeiro acesso cria a conexão
db1 = DatabaseConnection()
print(db1.connection)
# O segundo acesso reutiliza a mesma conexão
db2 = DatabaseConnection()
print(db2.connection)
print(db1.query("SELECT * FROM users"))
print(db1 is db2)Crie um gerenciador de configurações usando 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 - mesmas configuraçõesSaída:
True
140234567890123
140234567890123
Creating new database connection
Connected to MySQL database
Connected to MySQL database
Executing: SELECT * FROM users
True
TruePonto Chave: O padrão Singleton usa __new__ para controlar a criação de objetos, garantindo que apenas uma instância exista. Use-o para recursos que devem ter apenas uma cópia em toda a sua aplicação, como conexões de banco de dados, loggers ou gerenciadores de configuração. Lembre-se de que todas as variáveis que apontam para um Singleton referenciam o mesmo objeto na memória.
Desafio
FácilNeste desafio, você implementará o padrão de projeto Singleton para uma classe de conexão de banco de dados.
- Edite
databaseconnection.pypara implementar o padrão Singleton seguindo os comentários TODO - O arquivo
driver.pycontém cenários de teste extensivos e não deve ser modificado
Folha de consulta
O padrão Singleton garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a ela.
Implementação básica de Singleton usando __new__:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instanceO método __new__ controla a criação de objetos verificando se uma instância já existe antes de criar uma nova.
Testando instâncias de Singleton:
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # True - mesmo objetoExemplo prático com conexão de banco de dados:
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connection = "Connected to MySQL database"
return cls._instance
def query(self, sql):
return f"Executing: {sql}"Exemplo de gerenciador de configuração:
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)Use Singleton para recursos que devem ter apenas uma cópia em toda a sua aplicação, como conexões de banco de dados, loggers ou gerenciadores de configuração.
Experimente você mesmo
from databaseconnection import DatabaseConnection
# Manipulador abrangente de casos de teste
test_case = input()
if test_case == "identity_check":
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # Deve imprimir True
elif test_case == "connect_state":
db = DatabaseConnection()
print(f"Initial connected state: {db.connected}") # Deve imprimir False
db.connect()
print(f"After connect: {db.connected}") # Deve imprimir True
elif test_case == "disconnect_state":
db = DatabaseConnection()
db.connect()
db.disconnect()
print(f"After disconnect: {db.connected}") # Deve imprimir False
elif test_case == "multiple_instances_same_state":
db1 = DatabaseConnection()
db1.connect()
db2 = DatabaseConnection()
print(f"db2 connected state: {db2.connected}") # Deve imprimir True
elif test_case == "host_value":
db = DatabaseConnection()
print(f"Default host: {db.host}") # Deve imprimir "localhost"
db.host = "new-server"
db2 = DatabaseConnection()
print(f"New instance host: {db2.host}") # Deve imprimir "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}") # Deve imprimir True
print(f"Host value: {db1.host}") # Deve imprimir "custom-host"
elif test_case == "connect_message":
db = DatabaseConnection()
db.connect() # Deve imprimir "Connected to database at localhost"
elif test_case == "disconnect_message":
db = DatabaseConnection()
db.connect()
db.disconnect() # Deve imprimir "Disconnected from database"
elif test_case == "attribute_modification":
db1 = DatabaseConnection()
db1.port = 3306
db2 = DatabaseConnection()
print(f"db2 has port attribute: {hasattr(db2, 'port')}") # Deve imprimir True
print(f"db2 port value: {db2.port}") # Deve imprimir 3306
elif test_case == "reset_connection":
db1 = DatabaseConnection()
db1.connect()
print(f"Connected state: {db1.connected}") # Deve imprimir True
db2 = DatabaseConnection()
print(f"New instance connected state: {db2.connected}") # Deve imprimir True
db2.disconnect()
db3 = DatabaseConnection()
print(f"After disconnect, new instance state: {db3.connected}") # Deve imprimir False
elif test_case == "multiple_connects":
db = DatabaseConnection()
db.connect()
db.connect()
db.connect()
print(f"Connected state after multiple connects: {db.connected}") # Deve imprimir True
db.disconnect()
print(f"Connected state after disconnect: {db.connected}") # Deve imprimir False
elif test_case == "host_change_affects_message":
db = DatabaseConnection()
db.host = "custom-server"
db.connect() # Ainda imprimirá "Connected to database at localhost"
# O método connect possui uma mensagem fixa que não utiliza o atributo host
print("Message still shows localhost: True")Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosO Parâmetro selfMétodosAtributosMétodo Construtor (__init__)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Função super()Sobrescrita de MétodoHerança MúltiplaOrdem de Resolução de MétodosRecapitulação - Hierarquia de Funcionários7Métodos Especiais
Introdução aos Métodos MágicosSobrecarga de OperadoresMétodos Mágicos de ContêinerRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução a Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy2Decoradores
Introdução aos DecoradoresDecorador de PropriedadeDecorador de Método EstáticoDecorador de Método de Classe5Polimorfismo
Sobrescrita de Método RevisitadaDuck TypingClasses e Métodos AbstratosDesign de InterfacesRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição vs HerançaMixinsMétodos Estáticos e de ClasseDecoradores de ClasseGerenciadores de Contexto11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Propriedades de Classe
Variáveis de Instância vs de ClasseDecoradores de PropriedadeAtributos PrivadosRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Membros Públicos, Protegidos e PrivadosModificadores de AcessoOcultação de InformaçãoProperty Decorators AvançadosRecapitulação - Sistema de Registro de Alunos12Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário