Primeiras aulas do curso SOLID com Java: princípios da programação orientada a objetos

SOLID com Java: princípios da programação orientada a objetos

Orientação a Objetos - Apresentação

Olá pessoal. Sejam muito bem-vindos ao treinamento de SOLID. O meu nome é Rodrigo Ferreira e eu vou ser instrutor que vai acompanhar vocês durante esse treinamento. Nesse treinamento a proposta é aprendermos essa sigla SOLID, o que significa isso, quais são esses princípios e cada um dos 5 princípios do SOLID e ver como que podemos utilizar isso na prática em um projeto.

Vamos aprender sobre o princípio da responsabilidade única, o princípio aberto e fechado e o princípio da substituição de Liskov e o princípio da segregação de interface e o princípio da inversão de dependências. Então cada um desses princípios formam o SOLID que são princípios focados em boas práticas de programação e de orientação a objetos.

São extremamente importantes se você trabalha com uma linguagem orientada a objetos como o Java para você escrever um código que é fácil de manter e principalmente fácil de estender, de adicionar novas características, novos comportamentos, novas funcionalidades com um menor impacto possível. Não é muito comum termos projetos que conforme o tempo vai passando mais e mais funcionalidades vão sendo desenvolvidas, começa a ficar difícil de dar manutenção.

Você mexe em uma classe e ela quebra, outras 3, 5, 10 classes e você tem que ficar fazendo esse remendo, procurando onde que vai gerar impacto, procurando toda a mudança em quais classes que eu vou ter que mexer. Então esses princípios visam justamente simplificar esse processo de manutenção no seu código.

Então aqui no curso vamos ter um projeto que é um projeto bem simples, que é um projeto de um RH onde eu tenho lá os meus funcionários e eu preciso ter algumas funcionalidades como de conceder reajustes salariais, fazer promoção para o profissional subir de cargo. E essas funcionalidades vamos implementar e vamos ver alguns problemas no código e ver como podemos aplicar cada um daqueles princípios do SOLID para deixar o código muito mais simples e muito mais fácil de manter e de evoluir.

Então essa é a proposta do curso: podermos utilizar esses princípios em uma aplicação Java para deixar o código mais fácil de manter e de estender. Espero vocês na primeira aula e vamos ver como podemos aplicar esses princípios para deixar esse código um pouco mais fácil de manter e que você possa utilizá-los nos seus projetos pessoais e profissionais. Vejo vocês na primeira aula. Um abraço e até lá.

Orientação a Objetos - Coesão

Olá pessoal. Continuando o nosso treinamento de SOLID. Antes de falar sobre SOLID em si, eu queria fazer algumas discussões com vocês sobre alguns conceitos, alguns pilares importantes da orientação a objetos. São pilares que vamos tratar aqui durante o curso de SOLID e aí vamos ter um alinhamento melhor sobre as coisas que vamos discutir durante esse treinamento.

São três princípios que são mega importantes na orientação a objetos quando trabalhamos com uma linguagem orientada a objetos, Java, PHP, Python ou qualquer outra linguagem orientada a objetos. É o princípio da coesão, do encapsulamento e do acoplamento. Então conforme você estudou nos treinamentos de orientação a objetos, já deve estar familiarizado com esses termos.

Mas aqui eu quero fazer uma discussão só para alinharmos um pouco sobre esses conceitos e justamente no caso do SOLID, os princípios do SOLID estão diretamente ligados com esses princípios da orientação a objetos. Então quando aplicamos aqueles princípios do SOLID, vamos acabar aplicando também esses princípios da orientação a objetos, favorecendo uma melhor orientação a objetos no nosso código. O primeiro deles que eu quero discutir nesse vídeo com vocês é justamente sobre a coesão.

Coesão se formos parar para pesquisar, ler no dicionário o que é coesão provavelmente você vai chegar nesse significado ou algo do gênero, que é "União harmônica entre uma coisa e outra". Então coesão é justamente isso, quando você tem uma harmonia entre elementos. E aí aqui eu estou pensando de uma maneira genérica. Eu peguei do dicionário essa definição, não estou levando para área de software e nem em coisa do gênero. Mas se formos levar para software, o que seria essa harmonia?

No caso nós estamos pensando em uma classe. Vamos pensar que na orientação a objetos nós modelamos as coisas importantes do domínio da nossa aplicação com classes. Então, a união harmônica seria as coisas que tem dentro de uma classe. Os atributos e os métodos devem estar em harmonia, devem estar unidos e devem representar coisas em comum. Então aqui eu trouxe um exemplo de uma classe que vamos ter no nosso projeto, a classe "Funcionario".

Aqui seria um exemplo bom de uma classe que tem harmonia, uma classe que está coesa. Então percebe, é uma classe chamada "Funcionario" é a única coisa que tem ali dentro são atributos e métodos que representam o que é um funcionário no sistema.

Então eu tenho lá um atributo "nome", "CPF", "cargo", "salario" e tenho um método para dizer se um determinado "Funcionario" é um gerente. Então ele usa o "cargo" do "Funcionario", o atributo "cargo" para saber se é gerente ou não. Percebe, isso é um exemplo de uma classe coesa.

As coisas que tem dentro dessa classe estão em harmonia, estão tratando da mesma coisa, que no caso é da representação de um funcionário. Então não tenho coisas muito diferentes de funcionário dentro dessa classe, não que iria prejudicar a coesão. Aqui por outro lado eu fiz uma pequena modificação nessa classe "Funcionario". E aí aqui já temos um exemplo de uma classe não coesa.

Aqui a diferença é que na classe "Funcionario" eu tenho alguns outros atributos e são atributos referentes ao endereço do funcionário. Então eu tenho o "CEP", o "logradouro", "bairro", "cidade", "uf", enfim. Percebe que a classe começou a crescer e ficar muito grande, ficar com muitos atributos. Talvez isso seja um indício de que essa classe não está coesa. Aqui no caso, será que não seria melhor eu jogar todos esses atributos para uma classe "Endereco"?

Já que aqui eu não estou mais falando do "Funcionario", eu estou falando do "endereco". Óbvio, o funcionário tem o endereço, mas está muito detalhado, tem todos os atributos, todas as informações do endereço dentro, soltas na classe "Funcionario". Talvez fosse o seu caso de extrair isso para uma classe externa e deixar isso escondido dentro da classe "Endereco". E aí aqui também tem alguns métodos que talvez já estejam fugindo um pouco do objetivo da classe "Funcionario".

Então eu tenho um método para formatar um "CPF". Será que essa parte de "formatarCpf", ok, faz parte do funcionário, todo funcionário tem o CPF. Mas será que a formatação visual desse CPF deveria estar dentro da classe "Funcionario"? Será que não deveria ter uma outra classe que cuida só de formatação? E aí eu posso ter algumas variações da formatação com o ponto, sem os pontos, enfim. A mesma coisa, o outro método de formatar CEP. E o último que talvez seja o pior, "completarEndereco".

Eu coloquei um comentário aqui para não detalhar muito essa questão da lógica do código, mas aqui seria a ideia de consultar um WebService dos Correios para passar o CEP e recuperar os dados endereço, o logradouro, o bairro, enfim. Aqui seria um outro exemplo, será que a responsabilidade da classe "Funcionário" de fazer uma consulta, um serviço externo, buscar, fazer essa chamada a uma API externa, fazer um tratamento ou coisas do gênero. Então talvez aí já estava fugindo aquela harmonia, já perdeu a harmonia.

A classe está fazendo coisas demais. Então a classe deveria ter uma única responsabilidade. Isso é o que tem a ver com a coesão, você ter classes que fazem apenas uma única coisa, que é algo que vamos discutir bastante quando formos detalhar os princípios do SOLID. Então a ideia da coesão é justamente essa. Deixei essa frase aqui de resumo. "Classes não coesas tendem a crescer indefinidamente, o que as tornam difíceis de manter". Então provavelmente você já deve ter se esbarrado com isso em algum projeto.

Você pegou aquela classe que tinha 1000, 2000, 3000 linhas de código, tinha dezenas, centenas de atributos e de métodos e é bem provável que essa classe não é coesa porque ela deve estar fazendo coisas demais. Então acaba se tornando aquela classe muito maçante, muito difícil de dar manutenção. Qualquer coisa você tem que alterar essa classe e ela está fazendo coisas demais.

Você acabe se perdendo ali no meio, você pode ser código duplicado, enfim. A manutenção fica prejudicada quando temos classes não coesas. Então esse era um dos pilares da orientação a objetos que eu queria discutir com vocês nesse vídeo.

E ele vai ser bastante importante quando formos trabalhar e for entender e detalhar mais sobre os princípios do SOLID. Então na próxima aula vamos discutir sobre um outro princípio que também é importante da orientação a objetos e que também está lá diretamente relacionado com o SOLID. Então eu vejo vocês no próximo vídeo. Um abraço e até lá.

Orientação a Objetos - Encapsulamento

Olá, pessoal. Continuando nosso treinamento de SOLID. No último vídeo eu discuti com vocês sobre o princípio da coesão que é um princípio importante da orientação a objetos. Nesse vídeo eu quero falar sobre o segundo princípio da nossa lista que é o encapsulamento. Provavelmente você já se esbarrou com esse termo, já está familiarizado com esse termo e talvez você tenha uma visão errada e até incompleta sobre encapsulamento porque esse é um princípio que confunde um pouco.

Então vamos discutir sobre esse princípio aqui nesse vídeo. O encapsulamento, se você for pesquisar na internet ou no dicionário ou algo do gênero, você vai ver que encapsulamento significa o ato de você incluir e inserir algo em uma cápsula, você proteger alguma coisa independente do que seja essa coisa. E a ideia é justamente essa, você blindar. Então eu gosto de pensar dessa maneira no encapsulamento.

Agora trazendo para o nosso contexto de desenvolvimento de software e orientação a objetos. O encapsulamento nada mais é do que você proteger, blindar uma classe contra influências externas, contra manipulações externas que podem prejudicar a consistência das informações. Então isso que tem a ver com encapsulamento. E no geral temos uma visão errada do encapsulamento.

No geral aprendemos ou entendemos errado que encapsulamento é só pegar aquela classe, colocar os atributos como o "private", coloca lá o modificador "private" para deixar como privado e colocar os métodos "getters" e "setters" para fazer acesso a esses atributos de fora da classe. Só que na verdade isso não é que esteja errado, mas está incompleto. Não é só isso, o encapsulamento.

Encapsulamento tem outras questões importantes. E às vezes o fato de você simplesmente colocar "private" e colocar o geral, os métodos "getters" e "setters" pode ser que você esteja ferindo o encapsulamento, que você esteja criando lá um buraco digamos assim lá naquela cápsula que deveria proteger aquela classe. Então vamos ao exemplo de código. Aqui de novo a mesma classe "Funcionario". Aqui eu tenho um exemplo de como que seria a aplicação do conceito de encapsulamento.

No caso a classe "Funcionario" tem um atributo importante que é o salário. Inclusive, só para fins didáticos eu coloquei o salário aqui com double, mas no mundo real você colocaria como o big decimal. Aqui é só para facilitar. E a ideia é justamente essa. O salário é um atributo importante, ele tem validações, ele tem regras de negócio. Eu não posso alterar o salário de qualquer maneira, existem validações.

public class Funcionario {

    private String nome;
    private String cpf;
    private Cargo cargo;

// double apenas para fins didáticos
    private double salario;

    public void reajustarSalario(double aumento) {
        double percentualReajuste = (aumento / salario) * 100;

        if (percentualReajuste > 40) {
            throw new IllegalArgumentException(
                "percentual de reajuste deve ser inferior a 40%";
        }

        this.salario += aumento;
    }
}

Então para proteger, para encapsular o atributo "salario", foi criado esse método chamado "reajustar salário". Ele recebe o valor do aumento e faz uma validação. Aqui no exemplo que eu coloquei nesse código, o reajuste não pode ser maior do que 40% do salário. Então eu preciso fazer essa validação.

Toda vez que o método "reajustar salário" é chamado, a primeira coisa que é feita aqui no código é pegar o valor do aumento, comparar com o salário atual e ver qual é o percentual de aumento que está sendo concedido para esse funcionário e ele não pode ser maior do que 40%. O funcionário não pode receber mais que 40% de aumento, seria essa a regra. E aqui dentro desse método tem essa validação.

Se bateu nesse "if", se foi maior do que 40%, ele joga uma exception. Se não, se foi menor do que 40%, aí ele faz o incremento do salário do funcionário com o valor do aumento. Aqui tem um exemplo, um exemplo bom e positivo de encapsulamento. Eu estou encapsulando o salário que é um atributo da classe "Funcionario". A classe "Funcionario" está encapsulada.

Os atributos, quer dizer, pelo menos o atributo "salario" está protegido contra manipulações externas que possam violar essa regra de negócio, possam mexer diretamente no salário sem fazer essas validações. E vamos a um exemplo ruim que seria um exemplo clássico de você somente chegar na classe e colocar os atributos como "private" e gerar os métodos "getters" e "setters".

Aqui estaria um exemplo de violação no encapsulamento. Então a classe não estaria encapsulada, por mais que ela tenha os atributos privados. O método "set" seria o problema, o método "setSalario". Aqui seria esse exemplo. Eu não tenho mais aquele método "reajustar salário". Um exemplo que eu coloquei, finge que eu carreguei um funcionário lá do banco de dados, eu posso simplesmente pegar esse objeto "Funcionario" e chamar o método "setSalario" e passar um valor qualquer, por exemplo, 100 mil reais.

Não tem nenhuma validação, nenhuma regra sendo feita aqui, a não ser que essa regra esteja dentro do método "setter", mas no geral é aquele método "setter" tradicional que nem é você que digita. A IDE é que gera para você o método "getter" e "setter". Aqui seria um exemplo de violação do encapsulamento. Perceba que eu estou podendo acessar e manipular diretamente o atributo "salario".

Por mais que ele esteja privado, o método "setter" me permite isso. Permite que eu mexa diretamente no atributo e com isso eu consigo burlar regras de negócio. Eu não estou realizando aquela validação dos 40% de reajuste, eu estou fazendo reajuste de um valor indefinido. Percebe, é um exemplo ruim do encapsulamento. E esse tipo de coisa é o que tentamos evitar.

E os princípios do SOLID também vão favorecer com essa questão do encapsulamento. E aqui o resumo é do encapsulamento. Quando temos classes não encapsuladas, isso faz com que tenhamos violações da regra de negócio do projeto. Podemos ter classes com estados inválidos, com atributos, com valores que não deveriam ter e isso faz com que a classe tenha um aumento no seu acoplamento.

E é um outro que vamos discutir no próximo vídeo. Então espero que vocês tenham gostado dessa aula. Era só para discutir essa questão de encapsulamento e dar uma clareada nesse conceito importante da orientação a objetos e no próximo vídeo discutimos sobre o último princípio que é o do acoplamento que também é importante e vai influenciar os nossos estudos sobre o SOLID. Vejo vocês no próximo vídeo. Um abraço e até lá.

Sobre o curso SOLID com Java: princípios da programação orientada a objetos

O curso SOLID com Java: princípios da programação orientada a objetos possui 100 minutos de vídeos, em um total de 41 atividades. Gostou? Conheça nossos outros cursos de Java em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Java acessando integralmente esse e outros cursos, comece hoje!

Plus

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$85
à vista R$1.020
Matricule-se

Pro

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$120
à vista R$1.440
Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas