Рубрики
Без рубрики

Padrões de projeto com python

Padrões de projeto nesse artgo vamos abordar diversos padrões de projetos aplicados à lin … Tagged с Python.

Нессе Артиго Вамос Абордар Дайверы Падреес де Пехетос Апликадос à linguagem Python , E Buscar Centender Seu Funcionamento E Suas Contrivadeades.

Padrões comportamentais tendem detrinar o comportamento de objetos, классы e forma comoses se comunicam.

Стратегия Падран

O objetivo desse padrão é evitar que uma classe sosua maneiras diferentes de lidar com algo expectifico, дивидиндо када манера и криандо Ума Класс индивидуальный пара када эстратигия.

Em Python O Melhor Jeito de infular esse padrão é usando o módulo abc ( абстрактные базовые классы ) que nos fornece funcionalidades, классы e декораторы Para A CrioCão de Classes E Métodos Abstratos. Para Importion Os Essencial Para A Construção de Classes Abstratas Fazemos da Seguinte Maneira:

from abc import ABC, abstractmethod

Para Um Exememplo de Código, Vamos Imaginar Um Sistema Que Armazene Livros Em Uma Biblioteca, E A Biblioteca deve fornecer uma lista ordenada pelo título da obra, autor ou o isbn. Nossa classe biblioteca poderia ser infuladada da seguinte maneira:

class Biblioteca:
    def __init__(self, livros: List[Livro]):
        self.livros = livros

    def ordena_livros(self, campo_de_ordenacao: str):

        if len(self.livros) == 0:
            # Lógica para quando a lista de livros estiver vazia

        if campo_de_ordenacao == 'titulo':
            # Lógica para ordenar os livros por título
        elif campo_de_ordenacao == 'isbn':
            # Lógica para ordenar os livros por isbn        
        elif campo_de_ordenacao == 'autor':
            # Lógica para ordenar os livros por autor

MAS O Exemplo Acima não é Bom, Podemos dividir в роли Maneiras Como A Lista de Livros é Ordenada. Nesse Caso Podemos gerar uma classe abstrata para astratégia de ordenação que ficaria mais ou assim:

class EstrategiaDeOrdenacao(ABC):

    @abstractmethod
    def ordena_livros(self, lista_livros: Lista[Livro]):
        pass

class EstrategiaDeOrdenacaoPorAutor(EstrategiaDeOrdenacao):

    def ordena_livros(self, lista_livros: Lista[Livro]):
        # Lógica para ordenar lista de livros pelo autor

Classe Biblioteca Então Poderia Ser Reescrita de Uma Maneira Muito Mais Elegante Da Seguinte Maneira:

class Biblioteca:
    def __init__(self, livros: List[Livro], metodo_de_ordenacao: EstrategiaDeOrdenacao):
        self.livros = livros
        self.metodo_de_ordenacao = metodo_de_ordenacao

    def ordena_livros(self):

        if len(self.livros) == 0:
            # Lógica para quando a lista de livros estiver vazia

        return self.metodo_de_ordenacao.ordena_livros(self.livros)

Desse Jeito, Não Importa Que O Método de Ordenação seja baseado no autor, título ou waterquer autra coisa, pois a estratégia para ordenar a lista de livros foi abstada.

Команда Падран

O objetivo desse padrão éminuir o nível de acoplamento entre classe que se relacionam entre si de maneiras muito distintas. O Que o padrão propõe é a a a a a a a a a a a a ama de uma camada de comando única para todas в качестве классов, Mas que seja infervortualade para cada uma destas.

Num cenário em que estivesse sendo desenvolvido um jogo, no Qual o jogador, Através de um cliente, pudesse consertar objetos e/ou curar wootros personagens, представитель Poderíamos tais ações como a classe a seguir que queca cada o -osao:

class Invocador:

    def __init__(self, item: Equipamento, alvo: Personagem):
        self.item = item
        self.alvo = alvo

    def ativar(self):
        if self.item is not None:
            self.item.set_integridade(True)
        if self.alvo is not None:
            self.alvo.cura(20)

O Проблема Десса Абордагем é que gera umplamento muito grande intre que que voca как ações, e как классы que lidam com как azões. Medida Que O Jogo Fosse Sendo Atualizado, Mais ações seriam adicionadas e a classe Invocador precisaria ser odificada para lidar com elas, mas isso geraria mais acoplamento ainda.

Para solucionar isso aplicando o padrão command podemos criar uma class UMA Classe Que uppulta o Método Exemart.

class Comando(ABC):

    @abstractmethod
    def executar(self):
        pass

Dessa forma todos os atributos que precisamos ficam armazenados nas classes de comando, garantino que o acoplamento seja o menor возможно:

class CuraPelasMaos(Comando):

    def __init__(self, alvo: Personagem, valor_cura: int = 20):
        self.alvo = alvo
        self.valor_cura = valor_cura

    def executar(self):
        self.alvo.cura(self.valor_cura)


class Consertar(Comando):

    def __init__(self, item: Equipamento):
        self.item = item

    def executar(self):
        self.item.set_integridade(True)

Desse Modo, Podemos Adequar A nossa classe Invocador para deceber uma demandos, ao invés de modificar a classe para lidar com cada ação que pode serada.

class Invocador:

    def __init__(self):
        self.lista_de_comandos: List[Comando] = []

    def add_comando(self, comando: Comando):
        self.lista_de_comandos.append(comando)

    def rem_comando(self, comando: Comando):
        self.lista_de_comandos.remove(comando)

    def ativar(self):
        for comando in self.lista_de_comandos:
            comando.executar()

POR FIM TEMOS UM INVOCADOR QUE NãA PRECESA SABRE NADA SOBRE OS COMANDOS QUE IRESA, GARANTINDO UM Nível de Acoplamento Идеальный пара -термин Uma Boa Escalabiladadade. Caso o nosso jogador ossa Executar Uma omao Queba Quebra objetos ou causa dano aos inimigos, tudo que precisamos fazer é adicionar uma nova classe de comando ediconar a lista de comandos do invocador, tudo de maneira elegante.

PADRõES CRIACIONAIS TENDEM ОТДЕЛАННЫЙ МАНЕРАС ДЕ СЕ -ЛИДАР КАРАЦА ДЕБЕЙТОС, PARA SISTEMAS não sejam -зависимость Da crioCão, Composição e Recusticao de seus objetos.

Падран Синглтон

O objetivo desse padrão é garantir Que Que Нет Sistema Essecta Uma única Instância Da Classe. Esso служа, Mas Não Apenas, Para Garantir Centralização de Responseabilidade.

Em Python A Convincional de infularmos o padrão singleton é usando o Recurco de Metaclass Анкет Metaclass é A Solução em Python para quando uma classe precisa ter o conhecimento de manipular a si mesma. De maneira geral esse Recurco semper é usado por baixo dos panos, mas para o nosso padrão vamos precisar usá-lo явное.

Primeiramente Vamos Criar Nossa MetaClass:

class SingletonMeta(type):

    _instancias = {}

    def __call__(classe, *args, **kwargs):
        if classe not in classe._instancias:
            instancia = super().__call__(*args, **kwargs)
            classe._instancias[classe] = instancia
        return classe._instancias[classe]

Basicamente o Que fazemos é deginir um atributo “Privado”, Do Tipo Dicionário, Para a nossa classe, Que deve armazenar в роли Instâncias da Nossa Propria classe.

Fazemos isso ao sobrescrever o método __call__ Da Nossa Classe Cumentizada, de Modo Que Semper Que Seja Criado Uma Instância da Classe (Através da wamada ‘()’) seja arvificado no nosso dicionários se a nossa classe já esgine.

SE A Classe Já Extainir, nós retornamos a Instância armazenada no dicionário, caso crotrario criamos nossa primeira instância, chamando o método __call__ DA NOSSA CLASSE Mã REPASSANDO QUASQUER ARGISTOS QUE CECESBEMOS (OS NOSSOS *ARGS E ** KWARGS), E Armazenamos no Nosso Dicionário.

Por fim podemos ter uma classe que tenha a singletonmeta como Metaclass garantindo que o mesmo só sosua uma uma incia em todo o sistema. Como Por Exemplo, Uma Classe Para O Spooler de Impressão de Um Escritório:

class Spooler(metaclass=SingletonMeta):

    def __init__(self):
        self.impressoes: List[Impressao] = []

    def add_impressao(self, impressao: Impressao):
        self.impressoes.append(impressao)

Agora, Nãao importa Quantas Vezes seja instanciada a classe spooler, refertência vai ser semper para a primeira instância criada.

Прототип Падран

O objetivo desse padrão é garantir que nãa haja gaja incia do código do sistema nas situações em que seja preciso criar cópias de um deginado objeto. Pra tal o padrão detrina que cadase classe deva ser responseavel por infular seu proprio método de clonagem.

class Produto:

    __nome: str
    __preco: float

    def __init__(self):
        pass

    # Getters e Setters

    def clonar(self):
        produto = Produto()
        produto.set_nome(self.__nome)
        produto.set_preco(self.__preco)
        return produto

Da Maneira Como foi infuladado, não importa para wootros módulos do sistema sabre o que compões a classe produto, pois, caso precise de uma cópia de um objeto desse tipo, só precisa da watamade do método клонар () Анкет

PADRõES ESTRUTURAIS DIZEM RESPEITO à Composição de e objetos, E Apontam Meios de Como Estes Podem se unir para erar estrutura maiores.

Адаптер Падран

O objetivo desse padrão é garantir que seu código não tenha зависит от Com UMA DETRINADA BIBLIOTECA. Para Isso é proposto Адаптация интерфейса Criocão de Uma Que Padronize в роли Chamadas de Métodos, E que seja criado uma classe que aparta cada biblioteca utilizada herdando seus métodos.

Em Python, para lidarmos com o canceito de interfaces, классы Usamos Abstrata, e a classe que herda a abstrata deve uprevar todos os métodos Abstratos. Alem Disso Em Python Osuitymos uma funcionalidade que nione é presente em muitas autras linguagens: herança múltipla.

Herança múltipla nada mais é do Que a Que a Compacidade de uma classe herdar de duas classes mã diferentes, herdando seus atributos e métodos. Em Caso de atributos ou métodos com mesmo nome, o python desempata usando o critrio de Qual classe Foi Herdade Primeiro. Com Isso explicado Podemos prosseguir para nosso.

Vamos Imaginar Um Cenário em Que nosso sistema точный расчет. Para isso esectiem várias maneiras difendetes, e encontramos duas classes que entergam o restureado seguindo por abordagens отличается.

class Matemagica:

    def area_triangulo_tradicional(self, base: float, altura: float):
        # lógica para calcular área do triangulo


class Trigonomaestria:

    def area_triangulo_por_angulo(self, angulo_interno: float, lado1: float, lado2: float):
        # lógica para calcular área do triangulo com base no angulo interno

SE Optarmos por USAR UMA DELAS DIRETAMETE, NOSSO CODIGO FICARá -зависит Нет Носсо Кодиго.

Solução Já foi Apresentada, Vamos Criar Uma Classe Abstrata Para Adaptar O Que Esperamos Que Nossa Classe, независимый квалификация Escolheremos, Foca.

class ManipuladorMatematico(ABC):

    @abstractmethod
    def area_triangulo(self, base: float, altura: float, angulo_interno: float, lado1: float, lado2: float):
        pass

Em Seguida, Podemos criar Uma classe Que vai ser oursseavel por manipular cada uma das bibliotecas que utilizaremos, usando o recurso de heranta múltipla podemos herdar tanto da nossa classe abstrata, Quanto da classe da biblioteca.

class ManipuladorMatemagica(ManipuladorMatematico, Matemagica):

    def area_triangulo(self, base: float, altura: float, angulo_interno: float, lado1: float, lado2: float):
        return super().area_triangulo_tradicional(base, altura)


class ManipuladorTrigonomaestria(ManipuladorMatematico, Trigonomaestria):

    def area_triangulo(self, base: float, altura: float, angulo_interno: float, lado1: float, lado2: float):
        return super().area_triangulo_por_angulo(angulo_interno, lado1, lado2)

E Pronto, Criamos Nossos Proprios Adaptadores, E Quando для необходимости расчета Area de um triângulo no nosso sistema teremos Um Jeito único Независимый De Qual Classe Usemos.

    matematica: ManipuladorMatematico = ManipuladorTrigonomaestria()
    print(matematica.area_triangulo(5, 6, 45, 7, 8))

    matematica: ManipuladorMatematico = ManipuladorMatemagica()
    print(matematica.area_triangulo(5, 6, 45, 7, 8))

Мост Падран

O objetivo desse padrão é dividir uma classe em hierarquias, normalmente entre abstração, classe Que Irá Delegar Funcões, E upplainação, как классы que rao conter, как Funcionalidades, Essificas de uma parte do todo.

Para O Nosso Exemplo, Vamos Pensar Em Um Sistema Que Organiza gurgras de um jogo de rpg de mesa. Пенсандо NICHO DE RPG MEDIVAL, EMOMUM JOGOS DE RPG OSUIREM CLASS, OU Caminhos, Para O Personagem, Mas em Cada Jogo de Rpg Esso funciona de maneira отличается.

Com os recursos já apresentados até agora nesse artigo, podemos replectar esse padrão em python da seguinte maneira.

Primeiro criamos a classe de implementação, nesse exemplo vamos usar o guerreiro (o caminho mais comum em RPGs de mesa), e definir sua representação como uma classe abstrata, pois independente do jogo de RPG todos eles terão habilidades a serem listadas.

class Guerreiro(ABC):

    @abstractmethod
    def implementacao_listar_habilidades(self):
        pass

Em Seguida Vamos Criar Duas Classes Concetas Que Repprevam Guerreiros de RPGS отличается.

class GuerreiroT20(Guerreiro):

    def implementacao_listar_habilidades(self):
        print("Ataque Especial")


class GuerreiroDnD5E(Guerreiro):

    def implementacao_listar_habilidades(self):
        print("Estilo de Luta e Retomar o Fôlego")

Com As infulações concetas feitas, Podemos criar nossa classe de abstração e criar a ponte de fato.

class GuerreiroAbstrato(ABC):

    def __init__(self, implementacao: Guerreiro):
        self.implementacao = implementacao

    def listar_habilidades(self):
        self.implementacao.implementacao_listar_habilidades()

    @abstractmethod
    def usar_habilidade(self):
        pass

O nosso guerreiroaabstrato возможно, uma refemncia para uma umalaçaoo de guerreiro, Quequer Que seja ela. Нет примера, а Seguir, Na Classe Guerreiroinite Temos Abstração do uso de habilidades dos personagens gra Quelquer Rpg, Enquanto a classe guerreironpc abstrai que todos os npcs não usar habilidades Нет jogo.

class GuerreiroIniciante(GuerreiroAbstrato):

    def usar_habilidade(self):
        print("Usando: ", end="")
        self.listar_habilidades()

class GuerreiroNPC(GuerreiroAbstrato):

    def usar_habilidade(self):
        print("NPCs não podem usar habilidades")

Com Nossa infulação, nossa support guerreiro -não do jogo de rpg utilizado para usar suas próprias habilidades.

Нессе Артиго Абодамос Диверсион Э -Падреш де Пегетос де Тамбем Диверсии Типос. Espero ter alcançado o objetivo de conseguir e funcionamento e как конкретные Dos padrões uplecate na linguagem python. Até Aróxima.

Оригинал: “https://dev.to/arjom/padroes-de-projeto-com-python-65m”