Programação Orientada a Objetos
Tags: programming, oop, braziliandevs
Published: 2021-12-21 11:53:31

Para se entender programação orientada a objetos, primeiramente é necessário entender o que é um objeto. Um objeto é uma coisa material ou abstrata que pode ser percebida pelos sentidos e descrita por meio de suas características, comportamentos e estado atual. 

Partindo dessa definição, pode-se afirmar que objetos semelhantes possuem uma mesma classificação, tendo como exemplo de objeto um cachorro que é classificado como animal. Em programação orientada a objetos essa classificação é denominada classe. 

Ao se criar uma nova classe, é preciso que a mesma responda a três perguntas:
- Quais as características do objeto?
- Quais ações esse objeto realiza?
- Qual o estado desse objeto?

Realizando uma analogia com uma caneta obtém-se as seguintes respostas acerca das perguntas a cima:
- Uma caneta possui: modelo, cor, ponta, carga, tamanho, etc.
- Uma caneta pode: escrever, pintar, rabiscar, tampar, destampar, etc.
- Uma caneta está em estado de: 50% de carga,  ponta fina, cor azul, destampada, escrevendo, etc.

Nessa linha, segundo a teoria de Programação Orientado a Objetos, as perguntas podem ser entendidas como: 

- As características do objeto são chamados atributos
- As ações realizadas pelo objeto são chamadas métodos
- A maneira  que o objeto está nesse momento é chamado estado

Contudo, pode-se concluir que uma classe age como sendo uma forma na criação dos objetos, onde todo novo objeto irá possuir um padrão predefinido na classe.

Para criar um novo objeto é preciso instanciar a classe, na qual irá criar um novo objeto a partir do molde da classe.


## Vantagens
- Confiabilidade, o isolamento entre as partes gera software seguro. Ao alterar uma parte, nenhuma outra é afetada.
- Oportuno, ao dividir tudo em partes, várias delas podem ser desenvolvidas em paralelos.
- Manutenível, atualizar um software é mais fácil. Uma pequena modificação vai beneficiar todas as partes que usarem o objeto.
- Extensível, o software não é estático, ele deve crescer para ser útil.
- Reutilizável, podemos usar objetos de um sistema que criamos em um outro projeto futuro.
- Natural, mais fácil de entender. Você se preocupa mais na funcionalidade do que nos detalhes de implementação.


## Classes vs Objetos
Podemos entender classes e objetos como sendo conceitos interligados, onde um é depende do outro. A respeito das classes, podemos dizer que elas definem os atributos e métodos comuns dos objetos, que por sua vez, um objeto é uma instancia de uma classe. O exemplo a seguir ilustrará bem esses conceitos:

Imagine que tenhamos em mão uma forma de biscoitos. Essa forma não é um biscoito, no entanto, ela pode ser utilizada para gerar biscoitos. O objetivo dessa forma que assume o papel da classe é gerar biscoitos exatamente iguais, a partir dessa forma, é possível a criação de biscoitos, ou seja, objetos.


## Abstração de Objetos
Pode ser entendida como a simplificação de conceito, ou seja, abstrair apenas o essencial. Abstração é o ato de observar a realidade e dela abstrair ações e características consideras essenciais para uma determinada coisa. Objetos semelhantes possuem atributos semelhantes, no entanto, estados diferentes. O exemplo a seguir ilustrará bem esse conceito:

Suponhamos que em determinado momento um cliente requeira uma aplicação, onde serão vendidos apenas celulares na web. Tendo em mente que toda a lógica do seu sistema irá girar em torno da venda de celulares, podemos abstrair esse contexto, de modo que retiremos apenas o essencial, tais como o tamanho da tela, o fabricante, o modelo, o preço, entre outros atributos. Perceba que não é necessário abstrair dados como quantos transistores o processador do celular possui, pôs essa informação não é relevante para o cliente. Ademais, podemos abstrair métodos desses celulares, como por exemplo, calcular o frete ou a quantidade em estoque.

Abstrações não perduram em contextos diferentes, ou seja, a abstração de um  e-commerce de celulares difere de um catálogo de celulares.

Quando utilizamos programação orientada a objetos, devemos observar as características e os comportamentos de uma determinada entidade, para que possamos absorver essas informações e transforma-las em código.

Em alguns livros, a abstração é considerada como o primeiro pilar da Programação Orientada a Objetos.


## Modificadores de Visibilidade
Os modificadores de visibilidade indicam o nível de acesso aos componentes internos de uma classe, que são: atributos e métodos. A visibilidade irá informar qual o nível de acesso que se tem sobre eles. O exemplo a seguir ilustrará bem esse conceito:

Imagine um telefone. Podemos ter telefones públicos(popularmente conhecido como orelhão), telefones privados, e telefones protegidos. O que caracteriza um telefone público? Um telefone público é caracterizado como sendo algo que qualquer um pode usar. O que caracteriza um telefone privado? Um telefone privado é caracterizado como sendo algo que apenas o dono pode usar. E por fim, o que seria um telefone protegido? Imagine o telefone fixo da sua residência, apenas os membros da sua família poderão usar o telefone.

Definição de público, privado e protegido, segundo a Programação Orientada a Objetos:

- **Público:** todo atributo ou método definido como público ira definir que a classe atual e todas as outras classes possam ter acesso a elas.
- **Privado:** Apenas a classe atual terá acesso aos atributos e métodos.
- **Protegido:** Da acesso aos seus atributos e métodos a sua classe e todas as suas sub-classes.

## Pilares da Programação Orientada a Objetos
Para se entender os pilares da Programação Orientada a objetos, primeiramente é preciso entender o que é um pilar. Pilar é algo que dá sustentação a determinada coisa. Na Programação Orientada a Objetos existem três pilares:

### Encapsulamento
Encapsular é o ato de ocultar partes da implementação, permitindo construir partes invisíveis ao mundo exterior.

Um software encapsulado possui um mesmo padrão. A capsula age como uma proteção de dois lados, onde ela protege o código do usuário, e o usuário do código. O usuário não deve ter acesso ao funcionamento de uma classe, mas sim de sua capsula, que por sua vez, uma classe não dever ter acesso ao usuário. 

Exemplificando a teoria:

Observe uma pilha qualquer. Perceba que a pilha é uma capsula. No interior dessa pilha, estão contidas substâncias químicas que são prejudiciais a saúde. Graças a sua capsula não temos acesso a essas substâncias, mas sim, a energia por ela transmitida. Ademais, não poderíamos ter acesso as substâncias presentes em nessa pilha, devido elas serem prejudiciais, e a possibilidade de nós corrompermos seu funcionamento.

#### Relacionamento entre classes
O relacionamento entre classes como próprio nome propriamente diz, consiste em relacionar uma classe com outra. 

Exemplo de relacionamento:

Suponhamos que tenhamos uma classe caneta. Agora imagine que tenhamos várias canetas resultantes dessa classe caneta, ou seja, vários objetos que foram criados a partir dessa classe. Esse montante de objetos criados pode formar outra classe, onde tenham atributos como: quantidade, cor e preço; E os métodos: vender, comprar e pegarQuantidadeNoEstoque.

Perceba que no exemplo acima, uma nova classe foi criada a partir dos objetos gerados por uma outra classe, isso é relacionamento entre classes.

Podemos ter os seguintes relacionamentos:

- **Relacionamento de Agregação:** É um tipo especial de associação onde tenta-se demonstrar que as informações de um objeto (chamado objeto-todo) precisam ser complementados pelas informações contidas em um ou mais objetos de outra classe (chamados objetos-parte); conhecemos como todo/parte.

- **Relacionamento de Associação:** é o relacionamento entre duas classes independentes que em determinado momento se relacionam, ou seja, as classes se relacionam porém não depende umas das outras para existir.

- **Relacionamento de Composição:** é o relacionamento onde há dependência entre as classes, onde se uma classe progenitora deixar de existir, o filho também deixara de existir.

- **Relacionamento de Generalização:** é o relacionamento onde classes compartilham estados e comportamentos, ou seja, métodos e atributos. Define uma hierarquia de abstrações em que uma subclasse herda classes de uma ou mais classes.

#### Vantagens do Encapsulamento
- Torna mudanças invisíveis.
- Facilita a reutilização de código.
- Reduz efeitos colaterais.

#### Interface no Encapsulamento
No que diz respeito a visibilidade, pode-se afirmar que ela possui uma ligação com o encapsulamento, onde para que o encapsulamento funcione de maneira eficaz e correta, é preciso que aja um canal de comunicação. Esse canal de comunicação no encapsulamento é chamado interface. Sendo assim, um bom objeto encapsulado possui uma interface bem definida. 

Em outras palavras, interface, é uma lista de serviços fornecidos por um componente. É o contato com o mundo exterior, que permite o que pode ser feito com um objeto dessa classe.

Nessa linha, segundo a teoria de encapsulamento, na Programação Orientado a Objetos e o exemplo citado no tópico de encapsulamento, seus conceitos podem ser entendidos como: A pilha sendo a capsula e os polos da pilha sendo a interface

Estão presentes na composição de uma interface:
- **Métodos abstratos ou sobrescritos:** Qualquer classe que herda um método de uma superclasse tem a oportunidade de sobrescrever o método. O benefício de sobrepor é a capacidade de definir um comportamento que é específico para um tipo de subclasse particular.

- **Método construtor:** Tem a função de preparar o objeto para o usuário usar depois, ou seja são métodos especiais chamados pelo sistema no momento da criação de um objeto.

- **Métodos Get e Set:** Responsáveis pelo gerenciamento sobre o acesso aos atributos. Esse método determina quando será alterado um atributo e o acesso ao mesmo.

- **Métodos de Usuário:** Dentro da classe, declaramos o que cada objeto faz e como é feito. Irei usar como exemplo a classe Conta, onde simulamos uma conta de banco. Os métodos de usuário definem como um depósito ou um saque serão feitos. As funções que realizam isso, são chamadas de Métodos de Usuário.

Quando encapsulamos um objeto, em seu princípio, é de suma importância que aderimos a um conceito muito importante: torne todos os atributos privados, para que haja uma proteção da parte interna do objeto, fazendo com que, meios externos não possam interagir com seus atributos.

Para se utilizar a interface, é preciso que a mesma esteja implementada na classe. Para implementar, baste que na criação da classe, após seu nome, adicione a palavra implements e o nome da interface. Caso em sua interface estejam declarados métodos estáticos, é obrigatório que sobrescreva-os na classe.

### Herança
A herança permite basear uma nova classe na definição de uma outra classe previamente existente, podendo basear-se tanto nas características quanto nos comportamentos. Existem definições para essa situação:
- A classe que se baseia em uma outra classe é conhecida como classe filha, ou subclasse.
- A classe que se é  baseada é conhecida como classe mãe, superclasse, ou progenitora.

Exemplificando a teoria:

Utilizando novamente a analogia da caneta, imagine que se tenha uma classe de criação de canetas. Em determinado momento, se faz necessário a criação de uma nova caneta com características e ações semelhantes a primeira, no entanto, com algumas melhorias. É nesse contexto que a herança se encaixa. Basta que a classe de criação da caneta melhorada herde os atributos e métodos da caneta simples e após isso defina novos atributos e métodos conforme sua necessidade.

Agora imagine que em uma escola qualquer tenham alunos, professores e funcionários, e é preciso criar uma classe para cada um. Eles irão possuir as seguintes características e comportamentos:

- Aluno:
    - Características:
        - nome
        - idade
        - sexo
        - matrícula
        - sexo
    - Comportamentos:
        - fazer aniversário
        - cancelar matrícula
- Professor:
    - Características:
        - nome
        - idade
        - sexo
        - especialidade
        - salário
    - Comportamentos:
        - fazer aniversário
        - receber aumento
- Funcionário
    - Características
        - nome
        - idade
        - sexo
        - setor
        - trabalhando
    - Comportamentos
        - fazer aniversário
        - mudar de emprego

Perceba que algumas características e comportamentos se repetem entre eles, então basta que se crie uma quarta classe chamada pessoa, que irá possuir todas as características e comportamentos comuns entre eles. A partir daqui, as classes aluno, professor e funcionário irão herdar as características e comportamento da classe pessoa. 

#### Navegação Hierárquica
A navegação hierárquica consiste na representação das hierarquias das classes, onde uma classe independente que não seja herdeira é herdada por outras classes, que por sua vez, podem ser herdadas por outras classes. Esse processo se repete conforme a necessidade do projeto, podendo haver inúmeras classes mães e filhas. 

Quando a navegação é feita de de cima para baixo ela é chamada especificação, quando ela é feita de baixo para cima ela é chamada de generalização.

Essa navegação hierárquica pode ser entendi  da seguinte forma:

- A base dessa hierarquia será a classe independente que não é herdeira.
- Haverão sempre classes filhas, ou seja, classes que herdem de outra classe.
- Haverão sempre classes mães, ou seja, classes que são herdadas por outras classes.
- Podem haver classes descendentes, que são classes duas hierarquias abaixo de outra classe, sendo assim, neta.
- Podem haver classes ancestrais, que são classes duas hierarquias acima de outra classe, sendo assim, avó.

#### Tipos de Herança

- **Herança de implementação:** herda atributos e métodos de outra classe, no entanto ela não possui seus próprios atributos e métodos.
- **Herança para diferença:** herda atributos e métodos de outra classe, além de possuir seus próprios atributos e métodos.

### Polimorfismo
A noção de polimorfismo refere-se àquilo que dispõe ou que pode adoptar múltiplas formas. O termo também faz referência a uma propriedade capaz de atravessar numerosos estados.

#### Tipos de Polimorfismo
- **Sobreposição:** quando um método da classe mãe é sobreposto nas classes filhas, ou seja, substituído ou modificada. Para se obter a sobreposição de um método, é preciso que ele tenha a mesma assinatura(quantidade de atributos e os tipos dos atributos que serão passados no parâmetro do método) e estejam em classes diferentes.
    
    Para que a sobreposição seja realizada é preciso que um método abstrato seja criado na classe mãe e o mesmo seja sobreposto nas classes filhas. A sobreposição só pode ocorrer uma vez em cada classe filha.
    
- **Sobrecarga:** consiste em modificar um método da classe mãe através da classe filha, buscando se obter vários resultados diferentes a partir de suas assinaturas(quantidade de atributos e os tipos dos atributos que serão passados no parâmetro do método).
    
    A modificação do método deve ocorrer mais de uma vez em uma única classe filha, desde que suas assinaturas estejam diferentes umas das outras.

## Abstrato e Afim
- **Classe abstrata:** não pode ser instanciada. Só pode servir como progenitora.
- **Método abstrato:** declarado, mas não implementado na progenitora.
- **Classe final:** não pode ser herdada por outra classe.
- **Método final:** não pode ser sobrescrito por suas subclasses. Obrigatoriamente herdado.

---

Obrigado pela leitura ❤️

Linkedin: https://www.linkedin.com/in/pablo-caliari-ferrari-32bb7a1a8/

Github: https://github.com/PabloFerrari013