Quais são alguns exemplos de padrões de designs simples que podem ser usados em vários projetos? |
|
Ok, vamos explorar alguns padrões de design simples que podem ser úteis em vários projetos. Esses padrões são relativamente fáceis de entender e implementar, e podem melhorar significativamente a qualidade do código, a manutenção e a reutilização. 1. Singleton * Objetivo: Garante que apenas uma instância de uma classe seja criada e forneça um ponto de acesso global a essa instância. * Quando usar: Quando você precisa de um recurso único e compartilhado (por exemplo, gerenciador de configurações, pool de conexão de banco de dados, logger). * Exemplo simples (Python): `` `Python Classe Singleton: _instance =Nenhum def __new __ (cls, *args, ** kwargs): se não não cls.instance: cls._instance =super (singleton, cls) .__ novo __ (cls, *args, ** kwargs) # Inicialize a instância aqui, se necessário retornar cls._instance # Uso instância1 =singleton () Instância2 =Singleton () print (instance1 é a instância2) # saída:true (eles são o mesmo objeto) `` ` * Notas: Cuidado com singletons em ambientes fortemente multithread. Pode ser necessário adicionar mecanismos de travamento para garantir a segurança da linha durante a criação da instância. O uso excessivo de singletons pode levar a um acoplamento apertado e dificultar o teste. 2. Método da fábrica * Objetivo: Define uma interface para criar um objeto, mas permite que as subclasses decidam qual classe instanciar. Deseja o código do cliente da classe específica que está sendo criada. * Quando usar: Quando você precisa criar objetos de diferentes tipos com base em alguma condição ou configuração e deseja evitar codificar a lógica de criação de objetos diretamente no código do cliente. * Exemplo simples (Python): `` `Python Botão da aula: def render (self): Raise no notimplementEDerror () Classe htmlbutton (botão): def render (self): Retorne " Botão HTML " Classe WindowsButton (botão): def render (self): Retorne "Botão do Windows (específico da interface do usuário)" Classe ButtonFactory: def create_button (self, button_type): se button_type =="html": Retorne htmlbutton () elif button_type =="Windows": Retorne o WindowsButton () outro: Raise ValueError ("Tipo de botão inválido") # Uso Factory =ButtonFactory () html_button =factory.create_button ("html") Windows_button =Factory.Create_Button ("Windows") Print (html_button.render ()) # saída: Button HTML Print (Windows_button.render ()) # Saída:Botão do Windows (específico da interface do usuário) `` ` * Notas: O método da fábrica permite adicionar novos tipos de botões sem modificar a classe `ButtonFactory` diretamente (princípio aberto/fechado). 3. Estratégia * Objetivo: Define uma família de algoritmos, encapsula cada um e os torna intercambiáveis. A estratégia permite que o algoritmo varie de forma independente dos clientes que o usam. * Quando usar: Quando você tem várias maneiras de executar uma tarefa específica, e deseja alternar entre eles facilmente em tempo de execução. * Exemplo simples (Python): `` `Python Classe PaymentStrategy: Def Pay (self, valor): Raise no notimplementEDerror () CLASSE CREDERCARDCARDPAYMENT (PaymentStrategy): def __init __ (self, card_number, expiry_date, cvv): self.card_number =card_number self.expiry_date =expiry_date self.cvv =cvv Def Pay (self, valor): print (f "pagando $ {vale} usando cartão de crédito:{self.card_number}") Classe PayPalPayment (PaymentStrategy): def __init __ (self, e -mail): self.email =email Def Pay (self, valor): print (f "pagando $ {valor} usando o PayPal:{self.email}") Classe ShoppingCart: Def __init __ (self, paging_strategy:PaymentStrategy):# estratégia injetada aqui self.payment_strategy =pagex_strategy auto.total =0 def add_item (self, preço): auto.total +=preço def checkout (self): self.payment_strategy.pay (self.total) # Uso Credit_Card =CreditcardPayment ("1234-5678-9012-3456", "12/24", "123") PayPal =PayPalPayment ("[email protected]") Cart1 =ShoppingCart (Credit_Card) Cart1.add_item (100) Cart1.add_item (50) CART1.CHECKOUT () # Saída:Pagando US $ 150 Usando cartão de crédito:1234-5678-9012-3456 Cart2 =ShoppingCart (PayPal) Cart2.add_item (200) Cart2.Checkout () # Saída:Pagando US $ 200 usando PayPal:[email protected] `` ` * Notas: O `Shoppingcart` não precisa saber o método de pagamento específico. Ele simplesmente usa o injetado `PaymentStrategy` para executar o pagamento. Isso facilita a adição de novos métodos de pagamento sem modificar a classe `Shoppingcart`. 4. Observador * Objetivo: Define uma dependência um para muitos entre objetos para que, quando um objeto muda de estado, todos os seus dependentes sejam notificados e atualizados automaticamente. * Quando usar: Quando uma alteração em um objeto requer alterar outros objetos, e você não deseja que os objetos sejam fortemente acoplados. Exemplos:Manuseio de eventos, atualizações da interface do usuário, arquitetura de Model-View-Controller (MVC). * Exemplo simples (Python): `` `Python Assunto da aula: def __init __ (self): self._observers =[] def anex (self, observador): self._observers.append (observador) Def Detach (Self, Observer): self._observers.remove (observador) def Notify (self, mensagem): para observador em self._observers: Observer.Update (mensagem) Observador de classe: Def Update (self, mensagem): Raise no notimplementEDerror () Classe concreteobservera (Observer): Def Update (self, mensagem): print (f "Observer a recebido:{message}") Classe concreteobserverb (Observer): Def Update (self, mensagem): print (f "Observer b recebido:{message.upper ()}") # Uso sujeito =sujeito () observer_a =concretoobservera () observer_b =concreteobserverb () sujeito.attach (observador_a) sujeito.attach (observador_b) sujeito.Notify ("Hello, World!") # Saída:Observador A Recebido:Olá, mundo! # Observer B Recebido:Olá, mundo! sujeito.Detach (Observer_a) Subject.Notify ("Adeus!") # Saída:Observador B Recebido:Adeus! `` ` * Notas: O `sujeito` mantém uma lista de` observadores '. Quando o estado do `sujeito 'muda (neste caso, quando` notify` é chamado), ele itera pela lista e chama o método `update` em cada` observer`. 5. Método do modelo * Objetivo: Define o esqueleto de um algoritmo em uma classe base, mas permite que as subclasses substituam as etapas específicas do algoritmo sem alterar sua estrutura. * Quando usar: Quando você tem um conjunto de etapas que precisam ser executadas em uma ordem específica, mas algumas dessas etapas podem variar dependendo da implementação específica. * Exemplo simples (Python): `` `Python classe DataProcessor: DEF Process_data (self): self.read_data () self.validate_data () self.transform_data () self.save_data () print ("Processamento de dados completo.") def read_data (self): Raise no notimplementEDerror () def validate_data (self): Print ("Validação padrão:verificação dos valores nulos.")) def transform_data (self): Raise no notimplementEDerror () def Save_Data (self): Raise no notimplementEDerror () CLASS CSVDataProcessor (DataProcessor): def read_data (self): Imprima ("Lendo dados do arquivo CSV.") def transform_data (self): print ("Transformando os dados do CSV.") def Save_Data (self): print ("Salvar dados no banco de dados.") Classe JSondataProcessor (DataProcessor): def read_data (self): Imprima ("Lendo dados do arquivo json.") def validate_data (self): Print ("Validação personalizada para JSON Data:Checking Schema.")) def transform_data (self): print ("Transforming JSON Data.") def Save_Data (self): print ("Salvar dados no arquivo json.") # Uso csv_processor =csvdataprocessor () csv_processor.process_data () # Saída: # Lendo dados do arquivo CSV. # Validação padrão:verificando valores nulos. # Transformando os dados do CSV. # Salvando dados no banco de dados. # Processamento de dados completo. json_processor =jsondataprocessor () json_processor.process_data () # Saída: # Lendo dados do arquivo json. # Validação personalizada para dados JSON:Esquema de verificação. # Transformando dados JSON. # Salvando dados no arquivo json. # Processamento de dados completo. `` ` * Notas: O `DataProcessor` define a estrutura geral do algoritmo de processamento de dados. Subclasses como `csvdataprocessor` e` jsondataprocessor` fornecem implementações específicas para as etapas `read_data`,` transform_data` e `save_data`. A etapa `validate_data` pode ser substituída ou usar a implementação padrão. 6. Decorador * Objetivo: Adiciona dinamicamente responsabilidades a um objeto sem modificar sua classe. Os decoradores fornecem uma alternativa flexível à subclasse para estender a funcionalidade. * Quando usar: Quando você deseja adicionar funcionalidade a um objeto em tempo de execução, sem afetar outros objetos da mesma classe. Útil para adicionar registro, cache ou autorização. * Exemplo simples (Python): `` `Python Café da aula: def get_cost (self): retornar 5 def get_description (self): Retornar "Coffee" Classe Coffeedecorator: def __init __ (self, café): self._coffee =café def get_cost (self): retornar self._coffee.get_cost () def get_description (self): Retorne self._coffee.get_description () Classe MilkDecorator (CoffeeDecorator): def get_cost (self): retornar self._coffee.get_cost () + 2 def get_description (self): retornar self._coffee.get_description () + ", leite" Sugardecorator de classe (CoffeeDecorator): def get_cost (self): retornar self._coffee.get_cost () + 1 def get_description (self): retornar self._coffee.get_description () + ", açúcar" # Uso café =café () print (f "{Coffee.get_description ()} - custo:$ {Coffee.get_cost ()}") # saída:café - custo:$ 5 Milk_coffee =MilkDecorator (café) print (f "{Milk_coffee.get_description ()} - custo:$ {Milk_coffee.get_cost ()}") # saída:café, leite - custo:$ 7 Sugar_Milk_Coffee =Sugardecorator (Milk_Coffee) print (f "{Sugar_milk_coffee.get_description ()} - custo:$ {Sugar_milk_coffee.get_cost ()}") # saída:café, leite, açúcar - custo:$ 8 `` ` * Notas: O `Coffeedecorator` fornece uma classe base para os decoradores. Cada decorador (por exemplo, `MilkDecorator`,` Sugardecorator`) envolve o objeto `café" original e adiciona sua própria funcionalidade (neste caso, adicionando custo e descrição). Considerações importantes para escolher um padrão: * Entenda o problema: Defina claramente o problema que você está tentando resolver antes de buscar um padrão. Não aplique cegamente padrões; Use -os como ferramentas para melhorar seu código. * Simplicidade: Comece com a solução mais simples que atende às suas necessidades. Não engenharia as coisas prematuramente. * Contexto: O melhor padrão depende do contexto específico do seu projeto, do idioma que você está usando e da base de código existente. * Teste: Os padrões de design devem tornar seu código mais testável, não menos. Certifique -se de escrever facilmente testes de unidade para os componentes que está usando. Estes são apenas alguns exemplos de padrões de design simples. À medida que você ganha mais experiência, você aprenderá a reconhecer situações em que esses e outros padrões podem ser aplicados para criar código mais robusto, sustentável e reutilizável. Boa sorte!
|