Prévia do material em texto
Modelagem de Padrões de Projeto Aula 5 - Princípios SOLID Agenda do dia ➔ Princípios SOLID Vocês apresentarão os projetos em desenvolvimento. ➔ Exercícios Exercícios para praticar os princípios Os princípios SOLID ● Introduzidos por Robert Martin no livro Agile Software Development, Principles, Patterns and Practices. ● Têm como objetivo: ○ melhorar inteligibilidade ○ aumentar grau de flexibilidade ○ tornar os projetos mais sustentáveis ● CUIDADO! Existe um trade-off entre aplicar os princípios e a viabilidade do projeto como um todo. Imagem de kjpargeter no Freepik Os princípios SOLID Imagem de kjpargeter no Freepik Pilares da POO S L DIO Imagem de kjpargeter no Freepik Pilares da POO Single Responsibility Principle L DIO Imagem de kjpargeter no Freepik Pilares da POO Single Responsibility Principle L DIOpen/Closed Principle Imagem de kjpargeter no Freepik Pilares da POO Single Responsibility Principle Liskov Substitution Principle DIOpen/Closed Principle Imagem de kjpargeter no Freepik Pilares da POO Single Responsibility Principle Liskov Substitution Principle D Interface Segregation Principle Open/Closed Principle Imagem de kjpargeter no Freepik Pilares da POO Single Responsibility Principle Liskov Substitution Principle Dependency Inversion Principle Interface Segregation Principle Open/Closed Principle Single Responsibility Principle Foto: Freepik ● Cada classe deve ser responsável por apenas uma única parte da funcionalidade fornecida pelo software ● A responsabilidade deve estar totalmente inserida (encapsulada) na classe. ● Objetivo: redução da complexidade ● Se uma classe faz muitas coisas, você terá que mudá-la a cada mudança em cada uma das coisas. E, ao mudar uma das coisas, você corre o risco de quebrar as demais coisas. ● Ou então, quando uma classe tem várias responsabilidades, você pode ser obrigado a mudar coisas que não estão relacionadas com o propósito da mudança mas que estão tão conectadas com o ponto a ser mudado que é impossível não mudá-los junto. “Uma classe deve ter apenas uma razão para mudar.” SHVETS (2022) Estudo de caso SHVETS (2022) ● Qual é a responsabilidade que é incompatível com a classe Employee? ● O que pode acontecer se eu precisar reformatar o relatório, por exemplo? ● Como resolver esse problema? Estudo de caso SHVETS (2022) ● Qual é a responsabilidade que é incompatível com a classe Employee? ● O que pode acontecer se eu precisar reformatar o relatório, por exemplo? Dúvidas? ? ? ? ? ? ? ? ? ? Open/Closed Principle Foto: Freepik ● Objetivo: prevenir que o código existente quebre quando novas funcionalidades forem implementadas. ● Uma classe é aberta pode: ○ ser estendida ○ produzir uma subclasse ○ adicionar novos métodos ○ sobrescrever métodos existentes “As classes devem ser abertas para extensão mas fechadas para modificação.” SHVETS (2022) ● Uma classe é fechada (completa) quando: ○ está testada e pronta para uso ○ não será mudada no futuro ○ palavra-chave final Open/Closed Principle Foto: Freepik ● Quando uma classe está completa, convém não mudá-la para evitar quebras inesperadas em outros códigos. ● Mas, quando houver necessidade, pode-se estender a classe e criar subclasses modificando comportamentos da superclasse. “As classes devem ser abertas para extensão mas fechadas para modificação.” SHVETS (2022) Estudo de caso SHVETS (2022) ● O que acontece quando você tem que adicionar um novo método de envio? ● Adicionar métodos de envio tem a ver com os cálculos dos pedidos? Estudo de caso SHVETS (2022) ● O que acontece quando você tem que adicionar um novo método de envio? Dúvidas? ? ? ? ? ? ? ? ? ? Atividade 1 Considere a classes Chamado ao lado que gerencia os chamados (tickets) em execução e gera dois tipos de relatório: de manutenção e de produtividade. ● Desmembrar a classe Chamado em outras classes de modo a atender os princípios da responsabilidade única e aberto/fechado. ● Basicamente a ideia é replicar o que foi feito no slide anterior para o escopo da classe Chamado. Prazo de entrega: 3/9 23:59 Chamado + mecanicoResponsavel + data_inicio + data_fim + relatorios … + fechar() + geraRelatorio(tipo) … Atenção: Trabalhos em grupos devem ser enviados apenas por um membro do grupo. Os demais membros do grupo devem apenas marcar a caixa de presença! Liskov Substitution Principle Foto: Freepik ● Proposto por Barbara Liskov em Data abstraction and hierarchy (1987). ● Ao sobrescrever um método, estender o comportamento base ao invés de substituí-lo por algo totalmente diferente. ● Manter compatibilidade da subclasse com a superclasse. ● É um conjunto de verificações para garantir a compatibilidade de código “Quando estendendo uma classe, lembre-se que você deve ser capaz de passar objetos da subclasse em lugar de objetos da classe mãe sem quebrar o código do cliente.” SHVETS (2022) Liskov Substitution Principle Foto: Freepik Os tipos de parâmetros em um método de uma subclasse devem coincidir ou serem mais abstratos que os tipos de parâmetros nos métodos da superclasse. ● Suponha um método para alimentar gatos: ○ alimentar( Gato g ). ● Boa prática: sobrescrever para alimentar uma classe mais genérica: ○ alimentar (Animal a) ● Má prática: sobrescrever para alimentar uma classe mais específica: ○ alimentar (GatoSiames c) “Quando estendendo uma classe, lembre-se que você deve ser capaz de passar objetos da subclasse em lugar de objetos da classe mãe sem quebrar o código do cliente.” SHVETS (2022) Liskov Substitution Principle Foto: Freepik O tipos de retorno de um método de uma subclasse deve coincidir ou ser um subtipo do tipo de retorno no método da superclasse. ● Suponha uma classe com método para comprar gatos: ○ comprarGato(): Gato. ● Boa prática: sobrescrever a superclasse para retornar uma classe mais específica: ○ comprarGato(): GatoSiames ● Má prática: sobrescrever a superclasse para retornar uma classe mais genérica: ○ comprarGato(): Animal “Quando estendendo uma classe, lembre-se que você deve ser capaz de passar objetos da subclasse em lugar de objetos da classe mãe sem quebrar o código do cliente.” SHVETS (2022) Liskov Substitution Principle Foto: Freepik Um método em uma subclasse não deve lançar tipos de exceções que não são esperados que o método base lançaria. ● Suponha um método base que lança uma exceção do tipo CatNotFoundException. ● Boa prática: lançar uma exceção igual ou de subtipo do método base: SpecificCatNotFound ● Má prática: lançar uma exceção mais genérica: AnimalNotFound ● A maioria das linguagens já tratam esse princípio. “Quando estendendo uma classe, lembre-se que você deve ser capaz de passar objetos da subclasse em lugar de objetos da classe mãe sem quebrar o código do cliente.” SHVETS (2022) Liskov Substitution Principle Foto: Freepik Uma subclasse não deve fortalecer pré-condições. ● Suponha um método base que recebe um parâmetro inteiro. ● Má prática: estender a classe e sobrescrever o método para receber apenas inteiros positivos. ○ Quebra todo mundo que usava a classe base e passava um negativo sem problemas anteriormente. “Quando estendendo uma classe, lembre-se que você deve ser capaz de passar objetos da subclasse em lugar de objetos da classe mãe sem quebrar o código do cliente.” SHVETS (2022) Liskov Substitution Principle Foto: Freepik Uma subclasse não deve enfraquecer pós-condições. ● Suponha um método base que feche conexões de banco de dados ao retornar um valor. ● Caso você estenda a classe e mude este comportamento para reutilizar conexões abertas, o sistema pode nunca fechar nenhuma conexão e causar transtornos. “Quando estendendo uma classe, lembre-se que você deve ser capaz de passar objetos da subclasse em lugar de objetos da classe mãe sem quebrar o código do cliente.” SHVETS (2022) Liskov Substitution PrincipleFoto: Freepik Invariantes de uma superclasse devem ser preservadas. ● Invariantes são características comum a todos os objetos de uma classe. ● Nem sempre são óbvios pois podem estar implícito no domínio do problema. ● Portanto, ao estender uma classe, sempre preservar seus atributos e métodos, quando possível. “Quando estendendo uma classe, lembre-se que você deve ser capaz de passar objetos da subclasse em lugar de objetos da classe mãe sem quebrar o código do cliente.” SHVETS (2022) Liskov Substitution Principle Foto: Freepik Subclasses não devem mudar valores de campos privados da superclasse. ● Algumas linguagens permitem esse comportamento! “Quando estendendo uma classe, lembre-se que você deve ser capaz de passar objetos da subclasse em lugar de objetos da classe mãe sem quebrar o código do cliente.” SHVETS (2022) Estudo de caso SHVETS (2022) ● Possibilidade de salvar documentos somente leitura. ● Se eventualmente a aplicação salvar um documento somente leitura, vai lançar exceção! ● Violação do princípio aberto/fechado porque o código torna-se dependente de uma classe concreta (especializada). Estudo de caso SHVETS (2022) ● Agora, é impossível tentar salvar um documento somente leitura porque o método save() só está disponível na classe WritableDocument. Dúvidas? ? ? ? ? ? ? ? ? ? Interface Segregation Principle Foto: Freepik ● As interfaces devem ser o mais enxutas possível para que não haja a necessidade de implementação de muitos métodos que não serão utilizados. ● Quebra de interfaces “gordas” em classes mais especializadas. ● Risco de quebra se classes “gordas” forem modificadas. ● Herança permite extensão de apenas uma classe, mas uma classe pode implementar múltiplas interfaces. “Clientes não devem ser forçados a depender de métodos de que não usam.” SHVETS (2022) Estudo de caso SHVETS (2022) ● Repare os métodos não implementados da classe Dropbox. Estudo de caso SHVETS (2022) ● Observe que Amazon implementa inúmeras interfaces. Dúvidas? ? ? ? ? ? ? ? ? ? Dependency Inversion Principle Foto: Freepik ● Classes de baixo nível: Lidam com operações básicas como: ○ operações em disco ○ leitura e escrita de dados ○ trafegar dados na rede ● Classes de alto nível: lidam com a lógica de negócio e utilizam as classes de baixo nível para desempenhar determinadas operações. “Classes de alto nível não deveriam depender de classes de baixo nível. Ambas devem depender de abstrações. As abstrações não devem depender de detalhes. Detalhes devem depender de abstrações.” SHVETS (2022) Estudo de caso SHVETS (2022) ● Qualquer mudança na classe de baixo nível MySQLDatabase pode gerar mudanças no relatório de orçamento Estudo de caso SHVETS (2022) ● Dúvidas? ? ? ? ? ? ? ? ? ? Atividade 2 ● Modele uma classe Aeronave como implementação de pelo menos 4 subsistemas (ex: subsistema elétrico, hidráulico). ● Modelar 3 métodos em cada uma das interfaces, no mínimo. Referências SHVETS, Alexander. Mergulho nos Padrões de Projeto. Edição 2023-1.24. Kyiv: Refactoring.guru. 2022.