Padrão de projeto exposto: padrão de estratégia



Neste blog, vamos descobrir o Strategy Design Pattern, que é usado para criar uma família intercambiável de algoritmos que podem ser escolhidos dinamicamente.

'

Bem-vindo ao primeiro post da série “Design Patterns Exposed”. Nesta série, vamos descobrir cada Design Pattern a partir do zero.





O simples conhecimento de uma linguagem de programação e suas construções não o tornará um programador ou desenvolvedor melhor. Requer conhecimento de Design Patterns para criar software que funcione hoje e também no futuro.

Muitos desenvolvedores já se depararam com os problemas de design que você está enfrentando agora ou enfrentará no futuro. Eles especificaram uma maneira padrão de lidar com esse problema. Portanto, ao usar Padrões de Projeto, você obtém a vantagem de usar técnicas comprovadas.



Cada padrão de projeto é para resolver um determinado tipo de situação, pode haver situações em que mais de um padrão de projeto pode ser usado.

A maioria dos programadores apenas tenta resolver o problema que enfrentam sem se preocupar com padrões de projeto, código redundante ou mesmo acoplamento forte. Mas bons programadores começam de maneira diferente. Eles pensam sobre os requisitos de hoje, requisitos futuros, manutenção de código e reutilização de código.

Bons programadores não têm pressa em começar a codificar uma vez que atendam aos requisitos. Eles sentam e pensam sobre o problema de saber se seu projeto funcionará. Em caso afirmativo, se funcionará após 6 meses, quando os requisitos mudarão.



Bons programadores pegam papel e caneta e começam a projetar suas classes e o relacionamento entre as classes. Eles tentam obter um acoplamento fraco e alta coesão em seu projeto, enquanto fazem tudo isso, eles têm Princípios Orientados a Objetos em mente. Eles não entram no código de baixo nível imediatamente. Para criar um software flexível e reutilizável, você deve seguir esta abordagem, caso contrário, você sempre se verá modificando o código que escreveu anteriormente.

Só há uma coisa que é constante na indústria de software e é Mudança. Os requisitos certamente continuarão mudando. Então, como projetamos o software que seu código pode se adaptar facilmente aos requisitos futuros? Para isso, você deve começar cedo e projetá-lo de forma que os requisitos futuros não quebrem o código anterior.

Como eu posso fazer isso?

Bem, isso pode ser feito seguindo os Princípios de Design e Padrões de Design com base nesses princípios.

Agora, vamos mergulhar na codificação e começar a jornada para se tornar um programador melhor. Nesta postagem, vamos descobrir um dos padrões mais importantes - Padrão de Estratégia .

Quando digo o mais importante, isso reflete no problema comum que é resolvido pelo Strategy Pattern.

O que é padrão de estratégia?

Aqui está a definição diretamente do livro 'Gang of Four': “O padrão de estratégia é usado para criar uma família intercambiável de algoritmos a partir da qual o processo necessário é escolhido em tempo de execução”.

Caso você sejanão consigo entender, não se preocupe, vamos explicar em ummais simplescaminhopara ti tambémCompreendo.

Vamos primeiro entender o problema e depois ver como o padrão de estratégia pode resolver isso.

No diagrama UML acima, temos a classe abstrata Animal e duas classes concretas, Dog e Bird, estendendo-se da superclasse Animal.

Então, vamos definir uma classe abstrata Animal e duas classes concretas, Dog e Bird.

O que você acha do design acima? Existe um grande erro em nosso design.

Todos os animais não podem voar, como no caso acima, um cachorro não pode voar. Mas ainda tem comportamento de 'voar'.

Cometemos um erro ao escrever o método abstrato fly () dentro da classe Animal. Este design forçará cada subclasse Cão, Pássaro, Pinguim, Crocodilo, Ganso etc. a implementar o método fly ().

Devíamos ter entendido que voar é uma habilidade que nem todos os animais terão. Ao fornecer o método fly () na classe abstrata Animal, definimos a habilidade de vôo em todas as subclasses, o que não é correto para todas as subclasses de animais.

Você pode pensar qual é o problema em implementar o método fly nas subclasses. Embora você possa implementar o método fly () nas subclasses de Animais não-voadores para imprimir apenas 'Eu não posso voar'. Mas o problema é que você ainda está dando comportamento de mosca a animais que não voam. Isso não está correto.

Qual é a sensação de chamar dog.fly () ou crocodile.fly ().

Portanto, agora entendemos que nosso design não está correto e devemos remover o método fly () da subclasse Animal.

Qual é a outra maneira de projetar nossas classes de forma que nosso projeto não imponha que todas as subclasses de Animais tenham comportamento de mosca.

Uma solução que imediatamente vem à mente é que podemos fazer uma interface de vôo com o método voar e somente animais que podem voar irão implementar essa interface de vôo. Dessa forma, não forçaremos todas as subclasses de Animais para definir o comportamento de uma mosca. Então, vamos codificar essa abordagem de design.

Agora, nossa classe Animal se parecerá com o código abaixo após remover o método fly da classe Animal.

Agora vamos definir a interface do Flying

Agora, a classe Dog será alteradaComoo código abaixo e não precisa ter comportamento de voar.

Vamos ver algumas de nossas subclasses de Animais que terão comportamento de vôo.

Resolvemos nosso problema anterior, mas encontramos um novo problema, que é a “Duplicação de Código”.

Digamos que teremos 100 subclasses diferentes de Animais voadores. Temos que duplicar o código para o comportamento de voar, uma vez que a interface de vôo não pode fornecer nenhuma implementação para o comportamento de voar e, posteriormente, se quisermos mudar a implementação do método fly () em qualquer subclasse, teremos que abrir essa classe e alterar o código o que é ruim. Está faltando algo grande e, ou seja, não podemos mudar o comportamento de vôo de uma classe em tempo de execução.

Mas não se preocupe, o Strategy Pattern está aí para tirar você desse problema.

Então, vamos refatorar nosso código para usar o padrão de estratégia.

A interface de vôo permanecerá a mesma. Agora, em vez de cada subclasse de voo implementar a própria interface de voo, vamos definir classes concretas separadas que implementarão diferentes comportamentos de voo. Vamos ver como fazer isso.

Então, como tudo funciona, vamos ver o TestClass

Usando o Strategy Pattern, agora somos capazes de alterar o comportamento de vôo de qualquer animal em tempo de execução, sem forçar nenhuma subclasse para especificar o próprio comportamento de vôo.

Quando usar o padrão de estratégia?

Quando você deseja alterar o comportamento em tempo de execução de forma dinâmica.

Para ter certeza de que você entendeu claramente o padrão de estratégia, vamos dar outro exemplo.

Na classe de Funcionário acima, definimos o pagamento do funcionário de acordo com sua designação. Se o funcionário for um “Estagiário”, estamos adicionando um bônus de 10% ao salário base para calcular o salário real.

Se um funcionário for um “Desenvolvedor da Web”, estamos adicionando um bônus de 20% no salário-base para calcular o pagamento real e o processo semelhante segue para outros tipos de funcionários. Embora nosso algoritmo para calcular o salário real seja muito simples para torná-lo mais fácil de entender, na maioria das vezes, ele inclui muitas comparações e cálculos.

quais são as razões para criar uma instância da classe de arquivo?

Então, o que há de errado com o código de classe de funcionário?

Bem, o código para calcular o pagamento (getPay ()) é estático. Suponha que eu queira mudar o bônus para “Estagiário” de 10% para 14%. Terei que abrir o código da classe Employee e alterá-lo.

E outro problema é que não posso alterar o algoritmo de pagamento de um funcionário em tempo de execução. Então, como fazer isso? O Strategy Pattern é usado especificamente para lidar com esse tipo de problema.

Vamos refatorar o código para usar o padrão de estratégia.

Vou definir vários algoritmos para calcular o pagamento. Então, poderei usar qualquer um desses algoritmos para calcular o pagamento em tempo de execução.

Agora, vamos ver como a classe Employee vai mudar.

Nota: Removi a lógica de cálculo de pagamento da classe Funcionário e criei um método set PayAlgorithm () por meio do qual definirei o PayAlgorithm que desejo usar para o cálculo de pagamento.

Isso me dará a flexibilidade de calcular o pagamento especificando qualquer PayAlgorithm dinamicamente no tempo de execução. Além disso, observe que mais tarde, se eu tiver que alterar a lógica de cálculo do pagamento, posso criar um novo PayAlgorithm e usá-lo para calcular o pagamento. Não preciso alterar o código anterior, não é ótimo?

Então, vamos ver como funciona.

Espero que você tenha entendido o padrão de estratégia muito bem. A melhor maneira de aprender algo é praticando.

Caso você tenha alguma dúvida relacionada ao Strategy Pattern ou qualquer outro Pattern, deixe suas dúvidas abaixo.

Fique atento ao próximo post, onde descobriremos um dos padrões de design mais populares, o padrão de fábrica.

Até então, você pode baixar o código, brincar com ele e certificar-se de cimentar o padrão de estratégia em sua cabeça.

Tem alguma questão para nós? Mencione-os na seção de comentários e entraremos em contato com você.

Postagens relacionadas: