Pilares da programação orientada a objetos

A programação orientada a objetos (POO) é um paradigma amplamente usado no desenvolvimento de softwares. Adotado por linguagens de programação populares como Java e C#, por exemplo, o paradigma é aplicável a uma ampla variedade de projetos, desde os mais simples até os mais complexos.

A orientação a objetos busca aproximar o mundo real ao mundo da programação de computadores. A ideia central deste paradigma é que tudo aquilo que existe no mundo real pode ser representado em código através de objetos.

Para exemplificar, pense no sistema de uma universidade. Neste sistema, um aluno é representado como um objeto, com atributos e comportamentos específicos. Os atributos do objeto ‘aluno’ podem incluir matrícula, nome, data de nascimento, endereço, curso, disciplinas, entre outros. Os comportamentos podem englobar a realização de matrículas em disciplinas, cancelamento de matrículas, listagem de disciplinas matriculadas ou concluídas, cálculo de médias semestrais, entre outros. Da mesma forma, um professor, uma disciplina, um curso e qualquer outra entidade do sistema universitário pode ser representada como um objeto, com seus atributos e comportamentos próprios. 

Este artigo não possui a finalidade de detalhar os conceitos da POO, o foco aqui serão os quatro pilares fundamentais deste paradigma. Se você estiver interessado em conhecer mais sobre POO, clique aqui para ler um artigo que escrevi sobre esse assunto.  

1 – Os 4 pilares da programação orientada a objetos 

Os quatro pilares da POO representam quatro características que linguagens de programação e projetos devem atender para que sejam classificados como orientados a objetos. Essas características que formam os pilares da orientação a objetos são: abstração, encapsulamento, herança e polimorfismo.  

Abaixo vamos conhecer cada uma dessas características e na sequência vamos ver um projeto simples de Java, que simula operações bancária, criado para fins didáticos e que com certeza irá lhe ajudar no entendimento dos conceitos aqui apresentados.  

1.1 – Abstração 

A abstração está relacionada a capacidade de representar as coisas que existem no mundo real como objetos em um software. Os objetos devem ser identificados (nomeados) conforme sua função e devem possuir atributos (ou propriedades) e métodos (ou comportamentos) devidamente definidos e configurados.  
Pense, por exemplo, em um sistema bancário. Nesse sistema há um objeto chamado ContaBancaria, no qual temos atributos como número da conta, titular e saldo e temos também métodos como sacar, depositar, transferir e consultar saldo. Esse objeto é uma abstração de algo do mundo real (contas bancárias) representado em um software. 

1.2 – Encapsulamento 

O encapsulamento está ligado, diretamente, a segurança das informações do sistema. Ele pode ser entendido como uma forma de ocultação de dados.  

O encapsulamento restringe os acessos aos atributos e métodos dos objetos, evitando que ocorram acessos desnecessários que possam ocasionar mudanças indesejadas no sistema. A ideia é que cada objeto é responsável por manter a integridade dos seus dados (atributos), permitindo que sejam acessados somente através de métodos públicos específicos para essa finalidade.  

Vamos pensar no objeto ContaBancaria que apresentamos na explicação do conceito de abstração. É prudente que os seus atributos número da conta, titular e saldo sejam encapsulados e, portanto, acessados somente pelos seus métodos, a fim de evitar a exposição e manipulação dessas informações em outras partes do código. 

Nas linguagens de programação orientadas a objetos, o encapsulamento é alcançado através do uso de métodos de acesso (getters e setters) e modificadores de acesso (como public, private e protected). 

1.3 – Herança 

Herança é a característica de um objeto ou classe receber (herdar) atributos e métodos de um objeto ou classe superior. Assim, surge o conceito de classe mãe e classes filhas, as quais herdam atributos e métodos da classe mãe.  

Pensando novamente no exemplo do sistema bancário, nele temos uma classe chamada ContaCorrente  que é uma classe filha de ContaBancaria. Desta forma, a classe ContaCorrente herda os atributos (número da conta, titular e saldo) e os métodos (sacar, depositar, transferir e consultar saldo) da sua classe mãe ContaBancaria. Essa mesma regra valeria para outras classes filhas de ContaBancaria como, por exemplo, ContaDigital e ContaSalario.  

Note que, apesar de conta corrente, conta poupança e conta salário serem tipos diferentes de contas bancárias, todas compartilham os mesmos atributos e métodos básicos da classe ContaBancaria. Essa relação entre as classes, permitida pela herança, possibilita a reutilização de código, deixando o projeto mais organizado, legível e performático. 

1.4 – Polimorfismo 

O polimorfismo pode ser entendido como a característica da POO em que um mesmo método pode ter comportamentos diferentes conforme o objeto em que foi herdado.  

Para que possamos entender esse conceito, vamos imaginar a seguinte situação: o método consultarSaldo da classe ContaBancaria é herdado pelos objetos de conta corrente, conta digital e conta salário. A princípio, o método consultarSaldo deveria ter o mesmo comportamento em todos os tipos de contas, porém, nas contas correntes ele deve apresentar além do saldo disponível, o saldo de cheque especial daquela conta. Para contas poupança e salário deve ser apresentado somente o saldo da conta, pois, não há oferta de produtos de crédito nessas contas. Veja que se trata do mesmo método apresentando comportamentos diferentes conforme o objeto em que ele é usado.

2 – Entendendo os pilares da programação orientadas a objetos 

Após conhecermos a definição dos 4 pilares da programação orientada a objetos, vamos ver abaixo uma sequência de códigos escritos em Java, que simulam algumas transações bancárias. Esses códigos nos ajudarão a visualizar os pilares de programação orientada a objetos de forma prática, melhorando nossa compreensão a respeito do assunto.

2.1 – A estrutura do projeto 

Para executar os códigos em sua máquina você vai precisar instalar: a JDK 17 ou superior e uma IDE compatível com Java. Eu recomendo utilizar o IntelliJ ou o Visual Studio Code (se optar por esta opção não esqueca de instalar a extensão da linguagem Java). 

Depois de instaladas as ferramentas necessárias, você pode criar um projeto com a seguinte estrutura ou fazer o download do projeto disponível aqui:

Estrutura do projeto do sistema do banco.

Como podemos ver na imagem acima, a estrutura é bem simples e fácil de entender:

– Contas: é a pasta onde estão os arquivos que representam os tipos de contas que o banco fornece; 

– Enums: como o próprio nome sugere, é a pasta onde fica o arquivo de Enums da aplicação; 

– Models: pasta onde está a classe principal da aplicação; 

– Service: pasta onde fica a função que executa as ações da aplicação; 

– BancoApplicaton: arquivo onde está a função main() responsável por executar a aplicação. 

2.2- Entendendo os pilares da programação orientada a objetos no código

Abaixo, vou compartilhar alguns trechos dos códigos do projeto onde poderemos visualizar a aplicação de cada um dos pilares da programação orientada a objetos. Vamos lá!

public class ContaBancaria { 

    // Atributos da classe 
    private int numeroConta; 
    private String titularConta; 
    private double saldo; 


    // Construtor da classe 
    public ContaBancaria(int numeroConta, String titularConta,
                        double saldoInicial, TipoConta tipoConta) { 
        this.numeroConta = numeroConta; 
        this.titularConta = titularConta; 
        this.saldo = saldoInicial; 
    } 
  

    // Métodos da classe 
    public void depositar(double valor) { 
        saldo += valor; 
        System.out.println("Conta "+numeroConta+" - Depósito de R$" + valor + " realizado com sucesso!"); 
    } 

  
    public void sacar(double valor) { 
        if (valor <= saldo) { 
            saldo -= valor; 
            System.out.println("Conta "+numeroConta+" - Saque de R$" + valor + " realizado com sucesso!"); 
        } else { 
            System.out.println("Saldo insuficiente para saque de R$" + valor); 
        } 
    } 


    public void consultarSaldo() { 
        System.out.println("Conta: "+numeroConta+" / "+"Titular: "+titularConta+" / "+"Saldo atual: R$" + saldo); 
    } 

  
    public void transferir(ContaBancaria destino, double valor) { 
        if (valor <= saldo) { 
            saldo -= valor; 
            destino.saldo += valor; 
            System.out.println("Conta "+numeroConta+" - Transferência de R$" + valor + " realizada para a conta " + destino.numeroConta); 
        } else { 
            System.out.println("Saldo insuficiente para transferência de R$" + valor); 
        } 
    } 

  
    public double getSaldo() { 
        return saldo; 
    } 

    public int getNumeroConta() { 
        return numeroConta; 
    } 

    public String getTitularConta() { 
        return titularConta; 
    } 
} 

A abstração pode ser vista no código da classe ContaBancaria que replica algo que existe no mundo real (contas bancárias) através de um código de programação que será usado em um sistema computacional.  

Observe que a classe ContaBancaria foi construída com três atributos (número da conta, titular da conta e saldo) e quatro métodos (depositar, sacar, consulta saldo e transferir) que compõem a estrutura de uma conta bancária. A conta bancária é algo que existe no mundo real e utilizamos em nosso dia a dia e está sendo abstraída em um código computacional. 

Nesta mesma classe, também conseguimos ver o encapsulamento. Observe que os atributos numeroConta, titularConta e saldo foram definidos como private e, portanto, não podem ser acessados fora da classe ContaBancaria. A única forma de serem manipulados por códigos externos a essa classe é através dos getters definidos no código: getNumeroConta(), getTitularConta() e getSaldo(). 

public class ContaCorrente extends ContaBancaria { 
    
    private double chequeEspecial; 

    public ContaCorrente(int numeroConta, String titularConta, double saldoInicial, double chequeEspecial) { 
        super(numeroConta, titularConta, saldoInicial, TipoConta.CORRENTE); 
        this.chequeEspecial = chequeEspecial; 
    } 

    public double getChequeEspecial() { 
        return chequeEspecial; 
    } 

  
    @Override 
    public void consultarSaldo() { 
        double saldoTotal = getSaldo() + chequeEspecial; 
        System.out.println("Conta: " + getNumeroConta() + " / " + "Titular: " + getTitularConta() + " / " +  "Saldo atual: R$" + getSaldo() + " / Cheque Especial: R$" + chequeEspecial + " / Saldo Total: R$" + saldoTotal); 
    } 
}
public class ContaDigital extends ContaBancaria { 
    public ContaDigital(int numeroConta, String titularConta, double saldoInicial) { 
        super(numeroConta, titularConta, saldoInicial, TipoConta.DIGITAL); 
    } 
} 
public class ContaSalario extends ContaBancaria { 
    public ContaSalario(int numeroConta, String titularConta, double saldoInicial) { 
        super(numeroConta, titularConta, saldoInicial, TipoConta.SALARIO); 
    } 
} 

A herança pode ser vista nas classes ContaCorrente, ContaDigital e ContaSalario. Observe que, em todas elas, possuímos o comando extends ContaBancaria. Quando usamos a palavra reservada extends, indicamos ao Java que aquela classe irá herdar os recursos de uma outra classe, que, em nosso exemplo, é a classe ContaBancaria.  

Já o polimorfismo pode ser visto na classe ContaCorrente. Nesta classe é usada a anotação @Override que indica o polimorfismo na linguagem Java. Note que abaixo desta anotação, o comportamento do método consultarSaldo da classe ContaBancária está sendo alterado para apresentar uma informação exclusiva das contas correntes, que é o saldo de cheque especial do cliente.  

Conclusão 

De forma simples e resumida, neste artigo conhecemos os quatro pilares da programação orientada a objetos, os quais representam as características básicas das linguagens de programação orientadas a objetos.   

Recomendo que você analise, estude e edite os códigos para conseguir uma melhor compreensão dos pilares da POO. Procure entender estes conceitos e aprofundar seus conhecimentos neste paradigma de programação que é um dos mais utilizados no desenvolvimento de softwares.

Espero que o conteúdo aqui apresentado seja útil de alguma forma para você. Em caso de dúvidas, sugestões ou reclamações fique à vontade para entrar em contato. 

O que é HTTP? 

A internet revolucionou a forma como nos comunicamos e compartilhamos informações. Por trás dessa revolução, existem diversas tecnologias que garantem o funcionamento eficiente e seguro da web. Entre eles, destaca-se o HTTP (Hypertext Transfer Protocol) e sua versão segura, o HTTPS, os quais são pilares fundamentais para a comunicação entre dispositivos na internet. Neste texto, vamos entender o que são esses protocolos, como eles funcionam e qual sua importância para a segurança e eficiência da comunicação na internet. 

1 – O que é HTTP? 

O HTTP é um protocolo de comunicação entre dispositivos conectados em rede. HTTP é a sigla para Hypertext Transfer Protocol, que traduzido para o português significa, Protocolo de Transferência de Hipertexto. Conforme o próprio nome indica, este protocolo permite a transferência de documentos do tipo hipertexto entre dispositivos. Documentos hipertexto são documentos que possuem links clicáveis nas suas informações e podem direcionar o usuário para outros textos ou conteúdos, de maneira não linear. 

O HTTP é o protocolo de comunicação mais utilizado na World Wide Web (WWW). Quando você acessa um site, observe que a URL dele terá uma estrutura semelhante a essa: http://www.nomedosite.com.br.  

Veja que o endereço do site inicia com  http:// ou https://  indicando que estamos utilizando o protocolo HTTP para acessar aquele site.  

1.1 – HTTP e arquitetura cliente-servidor  

Representação gráfica  da arquitetura cliente servidor
Fonte: o autor

A internet funciona baseada na arquitetura cliente-servidor. Nesta arquitetura, um dispositivo chamado cliente, que pode ser um computador, notebook, tablet, televisor ou qualquer dispositivo com conexão à internet, realiza uma requisição (request) para um servidor que irá devolver uma resposta (response) para ele. Esta troca de informações entre cliente e servidor é feita por meio do protocolo HTTP, que define uma série de regras e padrões para comunicação online.  

2 – E o que é HTTPS? 

O HTTPS (Hypertext Transfer Protocol Secure – Protocolo de Transferência de Hipertexto Seguro) é uma evolução do protocolo HTTP.  

A transmissão de dados pelo protocolo HTTP não possui criptografia, assim se eles forem interceptados por terceiros podem ser facilmente lidos e entendidos. Esta era uma grave vulnerabilidade que comprometia a comunicação na internet. Foi para corrigir esta vulnerabilidade que surgiu o HTTPS. 

O HTTPS estabelece uma conexão segura e criptografada entre cliente e servidor, antes de transferir dados. Este protocolo utiliza as tecnologias de criptografia SSL e TLS em cada requisição e solicitação HTTP, tornando segura a transferência de dados na internet. 

3 – Como funcionam as requisições e respostas HTTPS? 

Como podemos perceber acima, o HTTPS é um protocolo fundamental para garantir uma navegação segura na internet. Mas você já se perguntou como acontece esse processo de comunicação segura entre cliente e servidor web?  

Quando acessamos um site ou enviamos dados através de um formulário online, uma série de processos ocorre nos bastidores para garantir que as informações sejam transmitidas de forma segura e eficiente. Vamos entender passo a passo como funcionam essas requisições e respostas HTTPS: 

–  Requisição realizada pelo cliente: quando o usuário acessa uma URL em seu navegador, por exemplo, uma requisição HTTPS é iniciada.  

Encontrar o IP do site: a primeira ação realizada é uma consulta ao servidor DNS para resolver o nome do domínio e encontrar o endereço IP do servidor onde o site está hospedado. 

Criação de conexão segura: após encontrar o IP, o navegador inicia um processo para estabelecer uma conexão segura com o servidor. Isto envolve a validação de certificados digitais e criar um canal seguro, criptografado, entre as partes. 

– Envio da Requisição HTTPS: com a conexão segura estabelecida, o navegador envia a requisição HTTPS ao servidor. As informações geralmente incluem o método HTTP (como GET, POST, PUT, PATCH ou DELETE), o cabeçalho da requisição e, às vezes, dados no corpo (como em formulários). Todos os dados são criptografados no navegador antes do envio ser realizado.  

Processamento da Requisição no Servidor: o servidor recebe a requisição, descriptografa-a e realiza seu processamento. Isso inclui realizar uma série de validações nos dados recebidos e consultar dados em bancos de dados para compor a resposta. 

– Resposta HTTPS do Servidor: após processar a requisição, o servidor prepara uma resposta, realiza sua criptografia e envia para o solicitante. Essa resposta contém o código de status HTTP (como 200 para sucesso ou 404 para não encontrado), cabeçalhos de resposta e, frequentemente, um corpo de resposta (em formatos como HTML, JSON ou XML). 

– Descriptografia da Resposta pelo Navegador: o navegador recebe a resposta criptografada e a primeira etapa para trabalhar com ela é fazer sua descriptografia.  Em seguida, os dados são processados pelo navegador e o resultado será renderizado na tela do dispositivo do usuário. 

– Fechamento da Conexão Segura: finalizada a comunicação entre as partes, a conexão SSL/TLS é encerrada. Em geral, cada requisição HTTPS estabelece uma nova conexão, embora métodos como Keep-Alive possam prolongar a conexão segura para várias requisições. 

Este processo de comunicação com o protocolo HTTPS, embora complexo em sua arquitetura, é otimizado para ocorrer em questão de milissegundos, proporcionando uma experiência fluida ao usuário. 

A velocidade da comunicação depende de diversos fatores, como a qualidade da conexão com a internet, o poder de processamento dos dispositivos envolvidos e a distância física entre cliente e servidor. Em condições ideais, com um hardware de boa qualidade e uma conexão de internet estável, todo esse ciclo de requisição e resposta acontece de forma praticamente instantânea, permitindo a navegação segura e ágil que conhecemos hoje.  

Esta alta eficiência é um dos pilares que possibilita a existência e expansão das aplicações web modernas e interativas, garantindo simultaneamente a segurança e a performance que os usuários buscam. 

Conclusão 

Como vimos, os protocolos HTTP e HTTPS são pilares fundamentais da internet. Enquanto o HTTP estabeleceu as bases para a comunicação na web, o HTTPS trouxe a camada de segurança necessária para proteger as informações transacionadas em ambientes online.  

A evolução desses protocolos reflete o desenvolvimento constante da internet, onde a busca por eficiência e segurança caminham lado a lado. Em um mundo cada vez mais conectado, compreender como essas tecnologias funcionam nos ajuda a entender melhor a infraestrutura que sustenta nossa vida digital e a importância da segurança na comunicação online. 

Gostou deste assunto e quer aprender mais sobre o protocolo HTTP? Clicando aqui, você tem acesso ao artigo que escrevi sobre Status Code. 

Espero que este artigo seja útil de alguma forma para você. Em caso de dúvidas, sugestões ou reclamações, fique à vontade para entrar em contato. 

O que é programação orientada a objetos? 

A programação orientada a objetos (POO) é um dos paradigmas mais conhecidos e utilizados na construção de sistemas computacionais. Baseada na ideia de aproximar o mundo real com o mundo da computação, a orientação a objetos nos permite estruturar o código de forma organizada e reutilizável, algo essencial para a construção de softwares robustos e escaláveis.

Neste texto, vamos explorar os fundamentos da orientação a objetos, seus conceitos-chave, e como aplicá-los na prática por meio de exemplos em Java, uma das linguagens mais populares nesse contexto. 

1 – Entendendo o conceito de programação orientada a objetos 

A programação orientada a objetos (OOP – Object-oriented programming) é um paradigma baseado no conceito de representar aquilo que existe no mundo real em sistemas computacionais através de classes e objetos.  

Esse paradigma serve como um modelo de análise, projeto e desenvolvimento de sistemas que procura aproximar o mundo real ao mundo da programação de computadores, tornando mais fácil o entendimento e solução de problemas complexos. 

Para entender esse paradigma pense, por exemplo, em um sistema bancário: nesse sistema temos uma classe principal chamada Conta Bancária. A partir desta classe, serão criados todos os tipos de contas bancárias disponibilizadas pelo banco. Note no exemplo abaixo que temos três tipos de contas: corrente, digital e salário. Estas contas e todas as demais que o banco vier a oferecer serão objetos da classe principal Conta Bancária. 

Representação gráfica da relação entre classes e objetos.
Fonte: o autor

Essa relação entre classe e objeto é a base do paradigma da programação orientada a objetos. Uma classe pode ser entendida como um modelo, enquanto os objetos, são tudo aquilo que construímos com base nesse modelo (classe). Quando um objeto é construído ocorre o que chamamos de instância de classe.  

Dessa forma, quando usamos os princípios da orientação a objetos para desenvolver um sistema, transformamos cada um dos requisitos em classes e objetos. E para cada uma dessas classes e objetos definimos atributos e métodos próprios que serão utilizados para processar os dados recebidos e retornar as saídas do sistema. 

1.1 – O que são atributos e métodos? 

Atributo e métodos são dois conceitos fundamentais na programação orientada a objetos e podemos entendê-los da seguinte forma: os atributos são as características de cada classe e objeto, enquanto os métodos são as ações e comportamentos dessas classes e objetos. Atributos e métodos são definidos nas classes e compartilhados pelos objetos instanciados através delas.  

Pensando na classe conta bancária, alguns exemplos de atributos podem ser: número da conta, titular da conta, saldo. Enquanto, exemplos de métodos podem ser: depositar, sacar, consultar saldo, transferir.

Representação gráfica detalhada da relação entre classes e objetos
Fonte: o autor

Analisando a imagem acima, percebemos que os atributos e métodos são inseridos na classe Conta Bancária. Dessa forma, cada conta bancária criada, independe do seu tipo, será um objeto instanciado da classe principal Conta Bancária e herdará todos os atributos e métodos disponíveis nela. E isto gera uma das principais vantagens da orientação a objetos: a reutilização de códigos. 

Observe em nosso exemplo que, todas as contas criadas, independente do seu tipo, herdam da classe principal todas as características e comportamentos comuns. Assim, não é necessário, por exemplo, reescrever o código responsável por consultar saldo para cada tipo de conta existente, pois, todas as contas herdam esse método da classe principal. 

2 – Exemplo prático de programação orientada a objetos 

Para fins didáticos e um melhor entendimento desses conceitos, vamos ver um exemplo simples de Java para representar a classe conta bancária.  

Se você quiser executar esse projeto na sua máquina, precisará ter o Java 17 instalado e uma IDE compatível com a linguagem como o IntelliJ ou Visual Studio Code, por exemplo.  

O primeiro arquivo de todo projeto Java é o Main.java, responsável por executar a aplicação, vamos criá-lo:

@SpringBootApplication 
public class BancoApplication { 
public static void main(String[] args) { 
ApplicationContext context = SpringApplication.run(BancoApplication.class, args); 
        BancoService bancoService = context.getBean(BancoService.class); 
        bancoService.ExecutaContas(); 

}
 

No arquivo Main.java nós estamos chamando a função ExecutaContas() da classe BancoService. Vamos criar um arquivo chamado BancoService.java: 

@Service 
public class BancoService { 
        public void ExecutaContas () { 
               ContaCorrente conta1 = new ContaCorrente(1, "João", 700.0, 200.00 ); 
               ContaDigital conta2 = new ContaDigital(2, "Maria", 500.0); 
               ContaSalario conta3 = new ContaSalario(3, "José", 1000.0); 

                conta1.consultarSaldo(); 
                conta2.consultarSaldo(); 
                conta3.consultarSaldo(); 
                conta1.depositar(200.0); 
                conta1.transferir(conta2,700.00); 
                conta2.sacar(500.00); 
                conta3.transferir(conta1,200.00); 
                conta1.consultarSaldo(); 
                conta2.consultarSaldo(); 
                conta3.consultarSaldo(); 
        }       

Note que o arquivo BancoService.java instância três objetos e executa uma série de ações que simulam as transações realizadas em um sistema bancário. 
 
Agora vamos criar as classes que representam os tipos de contas que instanciamos em BancoService: 

ContaCorrente.java

 public class ContaCorrente extends ContaBancaria { 
    private double chequeEspecial; 


    public ContaCorrente(int numeroConta, String titularConta, double saldoInicial, double chequeEspecial) { 
        super(numeroConta, titularConta, saldoInicial, TipoConta.CORRENTE); 
this.chequeEspecial = chequeEspecial; 
    } 


    public double getChequeEspecial() { 
        return chequeEspecial; 
    } 


    @Override 
    public void consultarSaldo() { 
        double saldoTotal = getSaldo() + chequeEspecial; 
        System.out.println( "Conta: " + getNumeroConta() + " / " + "Titular: " + getTitularConta() + " / " + "Saldo atual: R$" + getSaldo() + " / Cheque Especial: R$" + chequeEspecial +  " / Saldo Total: R$" + saldoTotal); 
    } 

ContaDigital.java 

public class ContaDigital extends ContaBancaria { 
    public ContaDigital(int numeroConta, String titularConta, double saldoInicial) { 
        super(numeroConta, titularConta, saldoInicial, TipoConta.DIGITAL); 
    } 

ContaSalario.java 

public class ContaSalario extends ContaBancaria { 
    public ContaSalario(int numeroConta, String titularConta, double saldoInicial) { 
        super(numeroConta, titularConta, saldoInicial, TipoConta.SALARIO); 
    } 

Veja que as classes Conta Corrente, Conta Digital e Conta Salário possuem a palavra-chave extends, indicando que elas herdam atributos e métodos da classe Conta Bancária. 

Vamos agora criar o arquivo ContaBancaria.java  que possui a classe principal Conta Bancária: 

public class ContaBancaria { 
    // Atributos da classe 
    private int numeroConta; 
    private String titularConta; 
    private double saldo; 

    // Construtor da classe 
    public ContaBancaria(int numeroConta, String titularConta, 
                         double saldoInicial, TipoConta tipoConta) { 
        this.numeroConta = numeroConta; 
        this.titularConta = titularConta; 
        this.saldo = saldoInicial; 
    } 

    // Métodos da classe 
    public void depositar(double valor) { 
        saldo += valor; 
        System.out.println("Conta "+numeroConta+" - Depósito de R$" + valor + " realizado com sucesso!"); 
    } 

    public void sacar(double valor) { 
        if (valor <= saldo) { 
            saldo -= valor; 
            System.out.println("Conta "+numeroConta+" - Saque de R$" + valor + " realizado com sucesso!"); 
        } else { 
            System.out.println("Saldo insuficiente para saque de R$" + valor); 
        } 
    } 

    public void consultarSaldo() { 
        System.out.println( 
                "Conta: "+numeroConta+" / "+"Titular: "+titularConta+" / "+"Saldo atual: R$" + saldo);  } 
    public void transferir(ContaBancaria destino, double valor) { 
        if (valor <= saldo) { 
            saldo -= valor; 
            destino.saldo += valor; 
            System.out.println("Conta "+numeroConta+" - Transferência de R$" + valor + " realizada para a conta " + destino.numeroConta); 
} else { 
            System.out.println("Saldo insuficiente para transferência de R$" + valor); 
        } 
    }

    public double getSaldo() { 
        return saldo; 
    } 

    public int getNumeroConta() { 
        return numeroConta; 
    } 

    public String getTitularConta() { 
        return titularConta; 
    } 

Observe que a classe ContaBancaria possui três atributos (numeroConta, titularConta e saldo) e quatro métodos (depositar, sacar, consultarSaldo e transferir). Essa é a classe modelo de onde conta corrente, conta digital e conta salário irão herdar atributos e métodos.  

Para finalizar, vamos criar um arquivo chamado TipoConta.java que será um Enum de tipos de contas: 

public enum TipoConta { 
    CORRENTE, 
    SALARIO, 
    DIGITAL 

Após finalizar a criação dos arquivos e códigos do projeto vamos executá-lo. Teremos esse resultado no console da IDE: 

 
Conta: 1 / Titular: João / Saldo atual: R$700.0 / Cheque Especial: R$200.0 / Saldo Total: R$900.0 
Conta: 2 / Titular: Maria / Saldo atual: R$500.0 
Conta: 3 / Titular: José / Saldo atual: R$1000.0 
Conta 1 - Depósito de R$200.0 realizado com sucesso! 
Conta 1 - Transferência de R$700.0 realizada para a conta 2 
Conta 2 - Saque de R$500.0 realizado com sucesso! 
Conta 3 - Transferência de R$200.0 realizada para a conta 1 
Conta: 1 / Titular: João / Saldo atual: R$400.0 / Cheque Especial: R$200.0 / Saldo Total: R$600.0 
Conta: 2 / Titular: Maria / Saldo atual: R$700.0 
Conta: 3 / Titular: José / Saldo atual: R$800.0 

Esses prints mostram os resultados das ações executadas na função ExecutaContas() da classe BancoService. Essas ações são realizadas pelos objetos de ContaCorrente, ContaDigital e ContaSalario, instanciados de ContaBancaria. Apesar de ser um simples exemplo, observe que através dele conseguimos visualizar claramente os conceitos fundamentais da programação orientada a objetos e entender melhor esse paradigma amplamente usado no desenvolvimento de software.

3 – Usando programação orientada no dia a dia 

A programação orientada a objetos está presente em praticamente todos os sistemas e aplicativos que utilizamos diariamente. Amplamente usada em serviços back-end, mas não restrita somente a isso, a orientação a objetos está presente em redes sociais, streaming de vídeos, jogos, ERPs e muitas outras aplicações que fazem parte de nosso cotidiano. 

Aprender e entender os conceitos de orientação a objetos é fundamental para desenvolver sistemas funcionais e eficientes, que atendam aos objetivos e requisitos definidos nos projetos que trabalhamos.  

A orientação a objetos também é suportada por muitas linguagens e tecnologias. No exemplo acima, usamos Java que, certamente, é a linguagem orientada a objetos mais conhecida no mercado. Entretanto, outras linguagens como C++, C#, Python, PHP e Kotlin e vários frameworks de desenvolvimento como Laravel, Djano, .NET e Flutter, aceitam os conceitos de POO. A escolha de qual linguagem e tecnologia usar dependerá, diretamente, das preferências do desenvolvedor e dos requisitos do projeto, dispondo de um amplo leque de opções para atender a todos os públicos. 

Mas, é válido lembra que, a programação orientada a objetos vai além dos conceitos de classes, objetos, atributos e métodos, apresentados acima. Outros quatro conceitos se destacam na programação orientada a objetos, são eles: abstração, encapsulamento, herança e polimorfismo. Esses conceitos são conhecidos como pilares da programação orientada a objetos e se você quiser saber mais sobre esse assunto, clique aqui, para ler um artigo que escrevi sobre este assunto.   

Conclusão 

A programação orientada a objetos é uma poderosa ferramenta para desenvolver sistemas funcionais, robustos e escaláveis. Sua estrutura baseada em classes, objetos, atributos e métodos permite organizar o código de forma clara, coesa e reutilizável, agilizando o desenvolvimento de sistemas.  

Ao compreendermos e aplicarmos esses conceitos, estamos melhor preparados para criar soluções tecnológicas que as expectativas de nossos clientes e usuários. 

Espero que este artigo seja útil de alguma forma para você. Em caso de dúvidas, sugestões ou reclamações, fique à vontade para entrar em contato. 

E se você quiser aprender mais sobre programação, acesse aqui a seção que tenho dedicada ao assunto.