Contents
Série Design Patterns em Python
- Introdução aos Design Patterns – Padrões de Projeto do GoF (Este artigo)
- O Padrão de Projeto Abstract Factory em Python
- O Padrão de Projeto Builder em Python
- O Padrão de Projeto Factory Method em Python
- O Padrão de Projeto Prototype em Python
- O Padrão de Projeto Singleton em Python (Este artigo)
- O Padrão de Projeto Adapter em Python (Em breve)
- O Padrão de Projeto Bridge em Python (Em breve)
- O Padrão de Projeto Composite em Python (Em breve)
- O Padrão de Projeto Decorator em Python (Em breve)
- O Padrão de Projeto Facade em Python (Em breve)
- O Padrão de Projeto Flyweight em Python (Em breve)
- O Padrão de Projeto Proxy em Python (Em breve)
- O Padrão de Projeto Chain of Responsibility em Python (Em breve)
- O Padrão de Projeto Command em Python (Em breve)
- O Padrão de Projeto Interpreter em Python (Em breve)
- O Padrão de Projeto Iterator em Python (Em breve)
- O Padrão de Projeto Mediator em Python (Em breve)
- O Padrão de Projeto Memento em Python (Em breve)
- O Padrão de Projeto Observer em Python (Em breve)
- O Padrão de Projeto State em Python (Em breve)
- O Padrão de Projeto Strategy em Python (Em breve)
- O Padrão de Projeto Template Method em Python (Em breve)
- O Padrão de Projeto Visitor em Python (Em breve)
Antes de mais nada, eu gostaria de deixar aqui o repositório no github que eu criei com os exemplos dessa série.
Portanto, se por acaso você quiser conferir todo o código que estamos escrevendo neste artigo, basta acessar o link:
O Que É O Singleton?
O padrão de projeto Singleton tem como objetivo garantir que exista apenas uma instância de um determinado objeto em sua aplicação.
Ele é comumente implementado utilizando um construtor privado, e um método estático que retorna uma instância da classe.
O Padrão de Projeto Singleton Em Python
Como você pode imaginar, o padrão de projeto Singleton em Python pode assumir diversas formas.
Tentando chegar próximo das implementações padrões do Singleton em outras linguagens, podemos implementar algo do tipo:
1 2 3 4 5 6 7 8 9 10 |
class Singleton: _instance = None @staticmethod def get_instance(): if Singleton._instance == None: Singleton._instance = Singleton() return Singleton._instance |
E podemos testar e conferir o resultado abaixo:
1 2 3 4 5 6 7 8 9 10 |
if __name__ == '__main__': singleton_1 = Singleton().get_instance() singleton_2 = Singleton().get_instance() singleton_3 = Singleton.get_instance() singleton_4 = Singleton.get_instance() print(singleton_1 is singleton_2) print(singleton_3 is singleton_4) print(singleton_1 is singleton_3) |
Singleton Utilizando O __new__
Nós podemos também sobrescrever o magic method __new__ para obtermos um comportamento semelhante:
1 2 3 4 5 6 7 8 9 10 |
class Singleton: def say_hello(self): print('Hello from {}'.format(id(self))) def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) return cls._instance |
E podemos testar o nosso exemplo tranquilamente:
1 2 3 4 5 6 7 8 9 10 11 |
if __name__ == '__main__': singleton_1 = Singleton() singleton_2 = Singleton() singleton_3 = Singleton() print(singleton_1 is singleton_2) print(singleton_1 is singleton_3) singleton_1.say_hello() singleton_2.say_hello() singleton_3.say_hello() |
Função Como Singleton
Nós podemos também criar uma classe “privada”, e retornar a instância desta classe através de uma função, que “simularia” a criação do objeto:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class _Singleton: _instance = None def say_hello(self): print('Hello from {}'.format(id(self))) def Singleton(): if _Singleton._instance is None: _Singleton._instance = _Singleton() return _Singleton._instance |
Note que utilizamos o underscore para declarar a classe Singleton, já que no Python, nós não temos como definir algo diretamente como privado, da mesma maneira que outras linguagens como o Java permitem.
1 After all, we're all consenting adults here
Você pode conferir esta frase no seguinte link: https://mail.python.org/pipermail/tutor/2003-October/025932.html
Lembrem-se, o Python confia em você 😉
Módulos e Funções como Singletons
Ao criarmos um modulo com funções, nós podemos obter o mesmo comportamento de um singleton.
Vamos criar um módulo chamado smodule, e adicionar o código abaixo nele:
1 2 |
def this_is_like_a_singleton(): print('Hello from a singleton as a func module') |
Ao utilizarmos o código, você poderá conferir que você pode importar este método várias vezes, e ele sempre sempre o mesmo:
1 2 3 4 5 6 |
from smodule import this_is_like_a_singleton as s1 from smodule import this_is_like_a_singleton as s2 if __name__ == '__main__': print(s1 is s2) |
Conclusão
O padrão de projeto Singleton é bem conhecido, e também muito polêmico.
Há diversas críticas ao padrão, e muitos o consideram um anti-pattern.
Eu sinceramente nunca vi ninguém pessoalmente escrevendo um Singleton em Python, apesar de infelizmente já ter visto arquiteturas inteiras baseadas em singletons em outras linguagens, como o C# por exemplo.
Apesar de não ser comum a utilização , é de extrema importância conhecer o Singleton em Python para que você possa utilizá-lo, ou então, evitar a sua implementação durante o seu dia a dia.
E ai, gostou do artigo? Ficou alguma dúvida? Não deixe de comentar abaixo!
Abraço 😉