Em Java, Princípios SÓLIDOS são uma abordagem orientada a objetos aplicada ao projeto de estrutura de software. É conceituado por Roberto C. Martin (também conhecido como Tio Bob). Esses cinco princípios mudaram o mundo da programação orientada a objetos e também mudaram a forma de escrever software. Também garante que o software seja modular, fácil de entender, depurar e refatorar. Nesta seção, discutiremos Princípios SÓLIDOS em Java com exemplo adequado .
A palavra SOLID é um acrônimo para:
- Princípio de Responsabilidade Única (SRP)
- Princípio Aberto-Fechado (OCP)
- Princípio de Substituição de Liskov (LSP)
- Princípio de segregação de interface (ISP)
- Princípio de Inversão de Dependência (DIP)
Vamos explicar os princípios um por um em detalhes.
Princípio de Responsabilidade Única
O princípio da responsabilidade única afirma que cada classe Java deve executar uma única funcionalidade . A implementação de múltiplas funcionalidades em uma única classe faz um mashup do código e se alguma modificação for necessária pode afetar toda a classe. Ele precisa o código e o código pode ser facilmente mantido. Vamos entender o princípio da responsabilidade única através de um exemplo.
Suponha, Estudante é uma classe que possui três métodos, a saber printDetails(), calcularPercentage(), e addAluno(). Conseqüentemente, a classe Aluno tem três responsabilidades: imprimir os detalhes dos alunos, calcular porcentagens e banco de dados. Ao utilizar o princípio da responsabilidade única, podemos separar estas funcionalidades em três classes distintas para cumprir o objetivo do princípio.
Aluno.java
public class Student { public void printDetails(); { //functionality of the method } pubic void calculatePercentage(); { //functionality of the method } public void addStudent(); { //functionality of the method } }
O trecho de código acima viola o princípio da responsabilidade única. Para atingir o objetivo do princípio, devemos implementar uma classe separada que execute apenas uma única funcionalidade.
Aluno.java
public class Student { public void addStudent(); { //functionality of the method } }
PrintStudentDetails.java
public class PrintStudentDetails { public void printDetails(); { //functionality of the method } }
Porcentagem.java
public class Percentage { public void calculatePercentage(); { //functionality of the method } }
Conseqüentemente, alcançamos o objetivo do princípio da responsabilidade única, separando a funcionalidade em três classes distintas.
Princípio Aberto-Fechado
A aplicação ou módulo entidade os métodos, funções, variáveis, etc. O princípio aberto-fechado afirma que de acordo com novos requisitos o módulo deve estar aberto para extensão, mas fechado para modificação. A extensão nos permite implementar novas funcionalidades ao módulo. Vamos entender o princípio através de um exemplo.
Suponha, Informações do veículo é uma classe e tem o método número do veículo() que retorna o número do veículo.
VeículoInfo.java
urfi javed
public class VehicleInfo { public double vehicleNumber(Vehicle vcl) { if (vcl instanceof Car) { return vcl.getNumber(); if (vcl instanceof Bike) { return vcl.getNumber(); } }
Se quisermos adicionar outra subclasse chamada Truck, simplesmente adicionamos mais uma instrução if que viola o princípio aberto-fechado. A única maneira de adicionar a subclasse e atingir o objetivo principal substituindo o número do veículo() método, como mostramos abaixo.
VeículoInfo.java
public class VehicleInfo { public double vehicleNumber() { //functionality } } public class Car extends VehicleInfo { public double vehicleNumber() { return this.getValue(); } public class Car extends Truck { public double vehicleNumber() { return this.getValue(); }
Da mesma forma, podemos adicionar mais veículos criando outra subclasse estendendo-se da classe de veículos. a abordagem não afetaria a aplicação existente.
Princípio da Substituição de Liskov
O Princípio da Substituição de Liskov (LSP) foi introduzido por Bárbara Liskov . Aplica-se à herança de tal forma que o classes derivadas devem ser completamente substituíveis por suas classes base . Em outras palavras, se a classe A for um subtipo da classe B, então deveremos ser capazes de substituir B por A sem interromper o comportamento do programa.
Estende o princípio open-close e também foca no comportamento de uma superclasse e seus subtipos. Devemos projetar as classes para preservar a propriedade, a menos que tenhamos uma forte razão para fazer o contrário. Vamos entender o princípio através de um exemplo.
bash para loop 1 a 10
Aluno.java
public class Student { private double height; private double weight; public void setHeight(double h) { height = h; } public void setWeight(double w) { weight= w; } ... } public class StudentBMI extends Student { public void setHeight(double h) { super.setHeight(h); super.setWeight(w); } public void setWeight(double h) { super.setHeight(h); super.setWeight(w); } }
As classes acima violaram o princípio de substituição de Liskov porque a classe StudentBMI tem restrições extras, ou seja, altura e peso que devem ser iguais. Portanto, a classe Student (classe base) não pode ser substituída pela classe StudentBMI (classe derivada).
Portanto, substituir a classe Student pela classe StudentBMI pode resultar em comportamento inesperado.
Princípio de segregação de interface
O princípio afirma que as interfaces maiores se dividem em interfaces menores. Porque as classes de implementação usam apenas os métodos necessários. Não devemos forçar o cliente a usar métodos que ele não deseja.
O objetivo do princípio de segregação de interfaces é semelhante ao princípio de responsabilidade única. Vamos entender o princípio através de um exemplo.
Suponha que criamos uma interface chamada Conversão tendo três métodos intToDouble(), intToChar(), e charToString() .
public interface Conversion { public void intToDouble(); public void intToChar(); public void charToString(); }
A interface acima possui três métodos. Se quisermos usar apenas um método intToChar(), não temos escolha para implementar o método único. Para superar o problema, o princípio nos permite dividir a interface em três interfaces distintas.
public interface ConvertIntToDouble { public void intToDouble(); } public interface ConvertIntToChar { public void intToChar(); } public interface ConvertCharToString { public void charToString(); }
Agora podemos usar apenas o método necessário. Suponha que queremos converter o número inteiro em duplo e o caractere em string, então usaremos apenas os métodos intToDouble() e charToString().
public class DataTypeConversion implements ConvertIntToDouble, ConvertCharToString { public void intToDouble() { //conversion logic } public void charToString() { //conversion logic } }
Princípio de Inversão de Dependência
O princípio afirma que devemos usar abstração (classes e interfaces abstratas) em vez de implementações concretas. Os módulos de alto nível não devem depender do módulo de baixo nível, mas ambos devem depender da abstração. Porque a abstração não depende do detalhe, mas o detalhe depende da abstração. Ele desacopla o software. Vamos entender o princípio através de um exemplo.
public class WindowsMachine { //functionality }
Vale a pena, caso não tenhamos teclado e mouse para funcionar no Windows. Para resolver este problema, criamos um construtor da classe e adicionamos as instâncias do teclado e do monitor. Depois de adicionar as instâncias, a classe terá a seguinte aparência:
public class WindowsMachine { public final keyboard; public final monitor; public WindowsMachine() { monitor = new monitor(); //instance of monitor class keyboard = new keyboard(); //instance of keyboard class } }
Agora podemos trabalhar na máquina Windows com a ajuda de teclado e mouse. Mas ainda enfrentamos o problema. Porque unimos fortemente as três classes usando a nova palavra-chave. É difícil testar a máquina Windows da classe.
Para tornar o código fracamente acoplado, desacoplamos o WindowsMachine do teclado usando a interface Keyboard e esta palavra-chave.
Teclado.java
public interface Keyboard { //functionality }
WindowsMachine.java
public class WindowsMachine { private final Keyboard keyboard; private final Monitor monitor; public WindowsMachine(Keyboard keyboard, Monitor monitor) { this.keyboard = keyboard; this.monitor = monitor; } }
No código acima, usamos a injeção de dependência para adicionar a dependência do teclado na classe WindowsMachine. Portanto, dissociamos as classes.
Por que devemos usar princípios SOLID?
- Reduz as dependências para que um bloco de código possa ser alterado sem afetar os outros blocos de código.
- Os princípios pretendiam tornar o design mais fácil e compreensível.
- Ao usar os princípios, o sistema é passível de manutenção, testável, escalonável e reutilizável.
- Evita o mau design do software.
Da próxima vez que você projetar software, tenha esses cinco princípios em mente. Ao aplicar esses princípios, o código será muito mais claro, testável e dispensável.