Defordição Do Projeto
Continuanto Essa Série De Posts Sobre Design Design, Já Foi Mastrado Como Usar em Java е Идти EGORA VAMOS MOSTRAR COMO USAR COM PYTON TAMPÉM, VAMOS VEMO COMO PADRões de Projeeto Nos Ajudam A Ter Um Código Limpo, Reutilizável E De Fácil Manutenção E ALTRAACHõES CASO CASORIO. Então Vamos Pensar No Cenário, Temos UMA Applicação Que Vai Salvar Notas Fiscais (счеты), Nesse Caso Vamos Ter Entrada de Vários Tipos Diferentes de Notas e Precisamos Processar Diferentemente CADA NOTA, Precisamos Descobrir Então E Exputar o Tipo de Nota Está cálculo de exputar a lógica de cálculo de toxuta Em Um Bucket Ou Até Mesmo Ur Arquivo TXT Smples Salvo Na Máquina E PIM FIM CENTERBEMOS СКОРОЖНАЯ ДЕ ЧЕСТА PARA CADA NOTA SALVA O DETACTO FISCAL E O Financeiro Querem Ser Neetados Disso.
Фабрика
Esse Padrão está no grupo dos padrões criacionais e nos ajuda quando precisamos Крэр рюадос EMME Superclasse, no nosso exemplo temos um domínio que seria a nota fiscal mas não sabemos que tipo de nota seria essa, será icms icms outs outra que ainda nem doversimos e que poy vir a avarecer por alguma exigência legal ou fiscal. (NãO SEI NADA SOBRE NOTAS FISCAIS PRA DIZER SE ICMS É UMA NOTA SOZINHA MAS O Exemplo Aqui é Para entender que que notas diferentes mas Нет Fim São Todas Notas Fiscais) Отказ Então Com Essa Ideia Vamos Criar O Super Tipo OU Интерфейс OU CLASSE Abrata, Isso Vária Um Pouco de Linguagem Pra Linguagem Mas A Aqui aqui é term “Molde” Para As a Nossas Notas, Vamos Kriar Classe Счетчик :
from abc import ABC, abstractmethod class Invoice(ABC): @abstractmethod def calculate_rate(self) -> str: pass
Aqui Temos A Nossa Classe Счетчик E ELA EMMA CLASSE ABTRATA COMM UM MÉTODO NãO ELIPEADO Chamado Calculate_rate Então Aqui Temos UMA CLASSE Que Nos Obriga A Ремонт Esse Método Para Quem Herdar Dela. Vamos Então Criar As Suas Filhas Que Serão как классы Сказочные моменты е Invoiceiss :
from factory.invoice import Invoice class InvoiceIss(Invoice): def calculate_rate(self) -> str: return "Processing Iss tax"
Как duas segoem o mesmo modelo para o nosso exemplo, Pra Simplifificar Temos Classe Que Herda UMA Счетчик Então Essa Classe. É UMA Счетчик E A Alloginação Do Método Calculate_rate Отказ Então Até Aqui Temos Só o que seria a estrutura ainda nada реферат Счетчик Eque Saiba é Uma Сказочные моменты Ума Invoiceiss :
from factory.invoice import Invoice from factory.invoice_iss import InvoiceIss from factory.invoice_icms import InvoiceIcms class InvoiceFactory: @staticmethod def create_invoice(name: str) -> Invoice: if name == "ICMS": return InvoiceIcms() else: return InvoiceIss()
A PAMEIRA VISTA UMA FACTORY DESSE TIPO NãO PARECE SER ALGO TãO Vantajoso E Que Não Tem Nada de Mais Com O Que Vemos No Nosso Dia-A-Dia Mas Para Esses Casos Eu Gosto de Citar o que is doxle bob a receito isso no livro Чистый код : «Solução é Inserir a Estrutura Shuta No Fundo de Uma Абстрактная фабрика e jamais deixar que alguém a veja. Фабрика Usará O Switch Para Criar Instâncias ApropriaDas Derivadas … Minha Revela Geral Para Estruturas Switch É Que São AceiTáveis Se Aparecerem apenas Uma rez, COMO Criação de objetos Polimórficos, E SE ESTAVEREM ESCONDIDIDAS, Atrás de Uma Relação de Herança de Mode Que o Resto Do Система Não Toxa Enxergá-ля. “
COMO NãO Temos Переключатель
EM Python Vamos Usar A Estrutura Если/else
Отказ POM FIM TEMOS COMO COMO CRIAR OS NOSSOS OBJETOS DE UMA FORMA MAIS Centralizada E Quem Chama A фабрика NãO SE PREOCUPA COM A FORMA QUE OS OBJETOS SãO Criados MAS SE PREOCUPAM SOMETE NA IDEIA DE USAR OS OBJETOS CRIADOS:
invoice_icms = "ICMS" invoice_iss = "ISS" invoice = InvoiceFactory.create_invoice(invoice_icms) print(invoice.calculate_rate()) invoice = InvoiceFactory.create_invoice(invoice_iss) print(invoice.calculate_rate())
Agora temos a nossa Счетчик Certa Sendo Construída e o Cálculo Correeto Pra Cada Tipo.
Адаптер
Agora Vamos Pensar Na Seguinte Situação, Temos o Nosso Cálculo Sendo Feito E O Processamento Acontecendo Mas Precisamos Heargar Esse Dado Em Algum Lugar, Mas Onde? Эм, Банко де Дадо, Мас Е.М. Enviz Esse Dado Em Um Sistema de Mensageria, Mas Qual? Кафка? Rabbitmq? Será que is élgo devemos nos precupar agora?
Pensando Na Ideia de AdvolationAção Tardia, OSDE ОС ДЕТАЛЬНЫЕ СЕРАО ПЕНСАНАДОС No Futuro E Que a nossa solução tem que ser pensada nogócio e nas nas tecnologias Envolvildas o Padrão Адаптер Nos Ajuda E Muito Com Isso.
IDEia Aqui é Que Eu Exponha Um Contrato DO Que Eu Preciso Que Seja Feito Esormente Será Alpeardada Solução, Vamos Cateçar A CRAR PARA Exemplififianar Melhor:
from abc import ABC from factory.invoice import Invoice class Repository(ABC): def save(self, invoice: Invoice): pass def get_one(self, identity: int) -> str: pass
Aqui Nós Temos a nossa Репозиторий Que Funciona Como O Nosso Contrato Talkenando Asinatura Dos Nossos Métodos SEM Axamplyação. Vamos Então Para A Aqui aqui aqui vamos SUPOR QUE PARA O NOSSO DESENVOLVEMATEMA E TESTES SOMENTE SALVANDO OS DADOS EM Им .текст É O Suficatee Para Nós, Então Criamos Assim:
from adapter.repository import Repository from factory.invoice import Invoice class FileSystemStorage(Repository): def save(self, invoice: Invoice): print(f"Saving with class {type(invoice). __name__ }") def get_one(self, identity: int) -> str: return f'FileSystemStorage#get_one'
Aqui é Só Um Emplo Básico Onde No Método спасти EU Exibo O Nome Da Classe Que Foi Passado E no get_one é devolvido uma string fixa, mas mesmo Essa Adverysação é Aderente Ao Contrato Do Nosso Адаптер Отказ AINDA VAMOS CRAR MAIS UMA CAMADA AQUI SO PARA EMAULE O CASO EM QUE Precisamos Fazer Alguma Proadação Pro Nosso Репозиторий :
from adapter.repository import Repository from factory.invoice import Invoice def save(repository: Repository, invoice: Invoice) -> None: print("Preparing to save") repository.save(invoice) def get_one(repository: Repository, identity: int) -> str: print("Preparing to get from storage") repository.get_one(identity)
PRONTO, COM ISSO JA PODEMOS USAR O NOSSO Адаптер EA Vantagem que temos é que conseguitimos seguir o nosso desenvollomos seguir o nosso desenvolvimento sem fiacar acoplado ou preso nenhuma tecnologia, se depois da nossa entrega для определения que vão unsar o banco de dados x ou o o trabalho que temos é clase outra classe que que use resse banco de Dados Mas que реализация носа Репозиторий E COM ISSO FICA TRASSPARENTE PRA QUEM USA ESSES DECHALHSES DE AIMLIESACãA, AQUI ABAIXO SEGE UM EMPELLO CASO USSSE UM BANCO DE DADOS:
from adapter.repository import Repository from factory.invoice import Invoice class Database(Repository): def save(self, invoice: Invoice): print(f"Loading specifics configs for the Database X") print(f"Saving with class {type(invoice). __name__ }") def get_one(self, identity: int) -> str: print(f"Loading specifics configs for the Database X") return f'Database#get_one'
E A Utilização Do Nosso Адаптер :
repository = Database() save(repository, invoice) get_one(repository, 1) repository = FileSystemStorage() save(repository, invoice) get_one(repository, 1)
Наблюдатель
AGORA JA PODEMOS КУРАБР АС NOSSAS СЧЕТЫ Occentendo Da Sua Entrada E Conseguimos Salvar SEM NOS Precupar COM ОС DEMALHS DE AIMINGASAS MAS AINDA FALTA O úLTIMO REQUISITO que é EnviR Para OS DEATADEDOS Interessados a Neetação de que Salvamos As СЧЕТЫ Отказ PodeMos Ao Fim de Cada Método Сохранить Fazer Algo Como:
sendEmail("dpt_financial") sendEmail("dpt_fiscal")
E ISSO VAI FUNCIONAR MAS VAMOS PENSAR QUE DRENTOU MAIS UM DETATEADO INTERESSADO NA CRIAçãO DE Счета OU ENTãO MUDOU REVERA E AGORA CADA PESSOA DESSES EALLADESESOS IRãAS CHEENBER E SãO 50 PESSOAS EM CADA SATETADETO.
Vamos FiCar Enthrando Semper No Código E Aumentar O Método Ou Fazer UM для
EMMA LISTA de Emails Ou Departamentos? E SE Tivesse Como Eu Me Increver Como Interessado Nesse Assunto E Toda Vez Que ЕС Им Сохранить Ocorerer ЕС Seja Notificado? Acredito que Seria Mais Smple Até Mesmo Caso Onde Eu Não Queira Mais Casher Onde Eu Não Queira Mais Main Me Desinscrever Nesse Assunto SEM Nenhuma.
Esse Seria O Padrão Наблюдатель Onde Eu Crio Crio Em Objeto Que Fica Lebalmente LuceAndo E Получение уверенности NoS Nos Assuntos Que Eu Me Inscrevi.
Então Vamos Crysar Criando A Nossa Classe Наблюдатель Que Vai Ser Repestyável POR КРИРПРАМЕНТ ДИДО ОС ОСУЩЕСТВЕННОСТИ E TEM TEM O MÉTODO QUE DIZ O QUE DEVE ACONTECER QUANDO UMA NETIFISACãO для ENVIADA:
class EmailObserver: def __init__ (self, email): self.__email = email def update(self, invoice): print(f'For {self.__email}, send report about {invoice}')
AQUI SO TEMOS O NOSSO INALIZADOR QUE REEACE BEA EMACT E O MÉTODO Обновление que получают Счетчик Para Montar Mensagem. EGORA VAMOS КРИАР О НОСО Тема que представление o nosso assunto a ser inscrito e que contém os métodos para se inscrever, desinscrever e neetifistar:
class EmailSubject: def __init__ (self): self.__subscribers = [] def add_email(self, subject): self.notify_subscribers(subject) def subscribe(self, subscriber): self.__subscribers.append(subscriber) def unsubscribe(self, subscriber): return self.__subscribers.remove(subscriber) def subscribers(self): return self.__subscribers def notify_subscribers(self, subject): for sub in self.__subscribers: sub.update(subject)
O Estado Interno Dessa Classe Contém Array de Подписчики Onde EU ADICONO UM NOVO OU REMOVO COM OS MÉTODOS Подписаться e Отписаться E O Método Para Notifitar Todos Os Inscritos Com notify_subscribers Отказ E Para Fazer Uso Dele Podemos Fazer O Seguinte:
fiscal = EmailObserver("dept_fiscal") financial = EmailObserver("dept_financial") subject.subscribe(fiscal) subject.subscribe(financial) subject.add_email("ICMS")
E COM ISSO Temos o Ganho de Inscrever Somente Uma Vez e Toda Vez que o add_email Для invocado Irá Notifearar Ados.
Projeto Complete
Segue Abaixo o Projeto Cellio E O Projeto нет Github :
from adapter.database import Database from adapter.file_system_storage import FileSystemStorage from adapter.adapter import save, get_one from factory.factory import InvoiceFactory from observer.email_observer import EmailObserver from observer.email_subject import EmailSubject invoice_icms = "ICMS" invoice_iss = "ISS" subject = EmailSubject() fiscal = EmailObserver("dept_fiscal") financial = EmailObserver("dept_financial") subject.subscribe(fiscal) subject.subscribe(financial) invoice = InvoiceFactory.create_invoice(invoice_icms) print(invoice.calculate_rate()) repository = Database() save(repository, invoice) subject.add_email(type(invoice). __name__ ) get_one(repository, 1) invoice = InvoiceFactory.create_invoice(invoice_iss) print(invoice.calculate_rate()) repository = FileSystemStorage() save(repository, invoice) subject.add_email(type(invoice). __name__ ) get_one(repository, 1)
Оригинал: “https://dev.to/guilhermegarcia86/padroes-de-projeto-com-python-62f”