DEV Community

Cover image for Programação Orientada a Objetos
Mayara Rysia
Mayara Rysia

Posted on • Updated on

Programação Orientada a Objetos

A Programação Orientada a Objetos (POO ou OOP, do inglês), é um paradigma de desenvolvimento de software ainda muito utilizado atualmente, é suportado por diversas linguagens de programação, a citar, C#, C++, VB.NET, Objective-C, Swift, PHP, Python, Ruby, Javascript, Java, e contrapõe o paradigma da programação procedural ou estruturada (procedural programming). Por meio da OOP nós podemos tornar o código organizado, reusável, mais seguro e de fácil manutenção.

O OOP foi empregado por Alan Kay na década de 60 durante a pós-graduação. A inspiração veio do Sketchpad de Ivan Sutherland pois representavam objetos como estruturas de dados com imagens gráficas exibidas em uma tela de osciloscópio.

A primeira linguagem de programação reconhecida como "Orientada a Objetos" foi a Simula, pois introduziu uma série de conceitos que formaram a base de OOP como a introdução de classes, herança e métodos virtuais. Alan Kay, com base nessa linguagem, foi co-criador da linguagem Smalltalk.

A grande ideia dele era usar minicomputadores encapsulados em software que se comunicava por meio de passagem de mensagens em vez de compartilhamento direto de dados.

"I made up the term 'object-oriented', and I can tell you I didn't have C++ in mind." (Alan Kay, OOPSLA '97)

De maneira básica, o Alan Kay resumiu o OOP em 3 ingredientes essenciais: message passing, encapsulation e dynamic binding, onde a combinação da message passing e encapsulation servem para os seguintes propósitos:

  • encapsular o estado por meio do isolamento de outros objetos e o controle das mudanças do estado somente será feito localmente;

  • desacoplar os objetos uns dos outros;

  • adaptabilidade do tempo de execução.

A ideia dele é que os objetos se comuniquem por passagem de mensagem. Suas ideias foram inspiradas em células biológicas e em estruturas algébricas.

Se você quiser conhecer mais sobre essa história, recomendo o artigo do Eric Elliot: The Forgotten History of OOP.

Nos dias atuais, o conceito da Programação Orientada a Objetos, representa elementos do mundo real abstraídos computacionalmente em forma de objetos, ou seja, um objeto é tudo aquilo que existe. Ele pode ser um animal, pessoa, carro, relógio e etc sempre a depender do contexto em questão.

Esses objetos são dados abstratos que possuem uma representação interna por meio de atributos de dados, que são as características daquele objeto, e uma interface para interação com objetos por meio dos métodos, que são os comportamentos do objeto com a implementação "escondida" que significa que poderemos executar as ações do objeto sem precisar entender como elas funcionam. Para facilitar a criação da representação do objeto com atributos e métodos pergunte-se: quais abstrações de dados compõem o meu objeto? E lembre-se sempre: nenhum objeto pode acessar os atributos de outros diretamente, apenas por meio dos métodos. Em suma, cada objeto é definido com suas próprias propriedades.

Vejamos alguns exemplos:

**Objeto Person**

Figura 1 - Objeto Person

Um Person (pessoa) tem as seguintes características: nome, data de nascimento, nacionalidade e cor. E ela faz as seguintes ações: ver, comer, andar, dormir, ouvir e falar.

**Objeto Coordinate**

Figura 2 - Objeto Coordinate

O exemplo foi retirado da aula Object Oriented Programming do MIT 6.0001 Introduction to Computer Science and Programming in Python, Fall 2016.

O ponto das coordenadas do plano é composto pela abscissa e ordenada portanto: x e y. Por meio desse objeto é possível revelar o valor de x e de y bem como realizar as atualizações deles e calcular a distância entre dois pontos do plano cartesiano.

Na notação visual Linguagem de Modelagem Unificada (UML) nós representaremos os objetos da seguinte maneira:

**Classe Person e Coordinate**

Figura 3 - Classe Person e Coordinate

OBS.: getters e setters são uma forma de obter e alterar os dados das classes (respectivamente), nem sempre são necessárias isso dependerá muito do contexto em questão.

Quando pensamos em criar um objeto abstraído da realidade nós estamos pensando também em criar nosso próprio dado, ou seja, nosso próprio tipo de dado. Em OOP nós modelamos os objetos usando o termo classe (class) e é por meio dela que nós podemos criar e usar nosso próprio tipo de dado.

Por exemplo, criei um tipo de dado Person que representa uma pessoa do mundo real. Considero que todo ser humano tem nome e data de nascimento (atributos) e realiza ações de andar, falar e comer (comportamentos):

public class Person {

    //attributes
    private String  name; 
    private Date dateBirth;

    //methods
    public void walk(){ ... }

    public void talk(){ ... }

    public eat(){ ... }

    @Override
    public String toString() {
          return "Name: "+ this.name 
           + "\nDate of Birthday: "+ this.dateBirth.toString();
     }
}
Enter fullscreen mode Exit fullscreen mode
Exemplo simples de uma classe pessoa na sintaxe Java

Vamos mapear mentalmente o conceito de tipo de dado com mais um exemplo: o objeto Coordenada feito na sintaxe Java.:

import java.lang.Math; 
public class Coordinate {
  // attributes
  private Double x;
  private Double y;

  // constructor
  // defined how to create an instance of this class
  public Coordinate(Double x, Double y) {
    this.x = x;
    this.y = y;
  }

  // methods
  public Double getX() {
    return x;
  }

  public void setX(Double x) {
    this.x = x;
  }

  public Double getY() {
    return y;
  }

  public void setY(Double y) {
    this.y = y;
  }

  public Double distance(Coordinate coordinate){
    Double abscissas = Math.pow((this.x - coordinate.x), 2);
    Double ordinates = Math.pow((this.y - coordinate.y), 2);
    return Math.pow((abscissas + ordinates), 0.5);
  }
}
Enter fullscreen mode Exit fullscreen mode
Classe Coordinate

Nesse exemplo, o construtor da classe define como se deve criar a instância dela , e sempre quando for criado o objeto do tipo Coordinate pela primeira vez, é necessário determinar x e y.

Logo, dados e procedimentos pertencem a classe.:

Atributos:

São os dados da classe. Vamos pensar neles como outros objetos que a compõe, como o objeto "name" do tipo de dado String que é um dado da classe Person, ou, do Objeto Person. E os dados x e y que são objetos do tipo de dado Double que pertencem a classe Coordinate.

Métodos:

São os procedimentos/comportamentos dos atributos que define como nós vamos interagir com o objeto. Vamos pensar neles como funções que trabalham na classe criada, como por exemplo, o comportamento de walk() ou talk() da pessoa, pertencem a classe Person.

Os procedimentos de alterar ou obter os valores das coordenadas foram definidos na classe Coordinate e somente assim é que podemos interagir com objetos desse tipo, portanto, se quisermos obter o valor da abscissa chamamos o método getX(), se quisermos mudar o ponto dela chamamos setX( novoValor ).

Por meio da classe Person, nós podemos criar diversos objetos que representam um ser humano, para isso é necessário criar a instância dessa classe conforme o exemplo:

class Main {
  public static void main(String[] args) {    
    // person1 object is of type Person
    Person person1 = new Person();

    person1.setName("Teddy");
    person1.walk(); // person1 walks

    // person2 object is of type Person
    Person person2 = new Person();
    person2.talk(); // person2 talks
  }
}
Enter fullscreen mode Exit fullscreen mode
Exemplo de instância da classe Person

Figura 4 - Resultado da manipulação de objetos do tipo Person.

Figura 4 - Resultado da manipulação de objetos do tipo Person

Por meio da classe Coordinate , nós podemos criar diversos objetos que representam pontos do plano cartesiano, e para isso é necessário criar a instância dessa classe e, para acessar os métodos, é obrigatório o uso do ponto (.) seguido do nome do método, pois, somente dessa forma, mantemos a interação com o objeto do tipo Coordinate. Vejamos o exemplo:

class Main {
  public static void main(String[] args) {
    Coordinate pointA = new Coordinate(5.0, 6.0); // (5,6) pointA object  is of type Coordinate
    Coordinate origin = new Coordinate(0.0, 0.0); // (0,0) origin object  is of type Coordinate

    System.out.println("abscissa - point A> x: " + pointA.getX() ); // abscissa - point A: 5
    System.out.println("abscissa - origin> x: " + origin.getX() ); // abscissa - origin: 0
    System.out.println("-- Distance: "+  pointA.distance(origin) ); //result: 7.81
  }
}
Enter fullscreen mode Exit fullscreen mode
Exemplo de criação dos objetos Coordinate e chamada de seus métodos

Figura 5 - Resultado da manipulação de objetos do tipo Coordinate

Figura 5 - Resultado da manipulação de objetos do tipo Coordinate

Só para não haver mais dúvida alguma quanto ao tipo de dado, vamos verificar em uma condicional o tipo de dado do objeto pointA na sintaxe Java:

if(pointA instanceof Coordinate) 
        System.out.println("type Coordinate");
Enter fullscreen mode Exit fullscreen mode
Condicional que verifica se o objeto pointA é do tipo Coordinate

Essa condicional é verdadeira e será impresso na tela o texto "tipo Coordinate".

Figura 6 - Resultado da manipulação de objetos do tipo Coordinate.

Figura 6 - Resultado da manipulação de objetos do tipo Coordinate

O OOP possui 4 princípios muito importantes:

  1. Abstração
  2. Encapsulamento
  3. Herança
  4. Polimorfismo

1. ABSTRAÇÃO

A abstração é uma das principais maneiras pela qual o ser humano lida com a complexidade. Ela divide um conceito em uma descrição simplificada ignorando detalhes sem importância e enfatizando os fundamentos necessários para aquele conceito, dentro de algum contexto.

A construção de um programa incluem elementos como funções, classes, enumerações e métodos. Na orientação a objetos, a abstração está ligada diretamente à noção de classe. Quando a abstração é usada para determinar os detalhes essenciais para algum conceito/problema, esses detalhes podem ser definidos em uma classe. É cabível a pessoa desenvolvedora escolher a abstração mais adequada ao contexto do desenvolvimento de software e ela deve ser compreendida antes de ser criada. Por exemplo, se queremos criar um aplicativo de exercícios de basquetebol, as características fundamentais de uma pessoa estão ligadas ao contexto de um atleta de basquetebol. Nesse sentido, portanto, as características fundamentais de uma abstração podem ser compreendidas de duas maneiras: por meio de atributos básicos e por meio de comportamentos ou responsabilidades básicas.

Logo, a abstração ajuda a obter o design das classes mais sucintas, focadas e compreensíveis a outra pessoa que as veem. Nela, é imprescindível considerar o que é relevante porque as abstrações dependem fortemente do contexto ou da perspectiva em questão.

2. ENCAPSULAMENTO

É uma maneira eficiente de manter os dados do objeto seguro porque a manipulação dos dados só deve ser feita por meio de procedimentos (métodos). Isso evita que haja uma alteração direta no dado da classe. Dessa maneira, o objeto vai expor apenas as informações que foram definidas através dos métodos. O encapsulamento, permite que objetos distintos criados a partir de uma classe específica tenham seus próprios valores de dados para os atributos e exibam os comportamentos resultantes. Isso torna a programação mais fácil porque os dados e o código que os manipulam estão localizados no mesmo lugar.

As 3 capacidades do encapsulamento são:

  • agrupar valores dos atributos (ou dados) e comportamentos (ou funções) que manipulam esses valores, em um objeto autocontido;

  • expor dados e funções desse objeto, que pode ser acessado por outros objetos (pode ser por meio de uma interface);

  • restringir o acesso a certos dados e funções dentro do objeto.

No exemplo da classe Coordinate , somente é possível alterar um valor da coordenada por meio do método setY(6) ou setX(9) e não diretamente com Coordinate.y = Null. Além disso, o encapsulamento assegura que quem estiver utilizando esse método não precisa saber como foi feita a implementação, pois apenas o chama e ele realiza a ação.

Portanto, esse princípio mantém o software modular e fácil de trabalhar e as classes são fáceis de gerenciar, porque seu comportamento interno não é relevante a outras classes e elas podem interagir juntas.

3. HERANÇA

A herança nos permite reutilizar informações de uma classe principal. Uma classe herda informações de outra classe, que são os atributos ou comportamentos, e por conta disso ela será filha da classe mãe. Em outras palavras, a classe que recebeu herança é chamada de subclasse, ela herda os dados e os comportamentos da classe mãe (superclasse). Vejamos um exemplo:

Representamos uma pessoa com a classe Person e agora nós vamos representar um objeto funcionário. Nós sabemos que todo funcionário é uma pessoa, um ser humano, então ele herda todas as características de um ser humano e seus comportamentos. Mas embora o funcionário herde os dados da classe Person, ele possui seus próprios dados dentro da empresa em que atua:

Figura 7 - Representação de um Objeto Employee

Figura 7 - Representação de um Objeto Employee

Nós percebemos características da representação do objeto Person e mais duas que pertencem apenas a Employee: identificação ( que seria uma matrícula) e departamento, que nesse exemplo, a funcionária Maria está no departamento de TI, além disso, a funcionária possui a ação de trabalhar.

Na notação visual Linguagem de Modelagem Unificada (UML) nós representaremos os objetos em classes da seguinte maneira:

Figura 8 - Classe Person e Employee

Figura 8 -Classe Person e Employee

Na linguagem java utilizamos o extends para indicar herança:

public class Employee extends Person {

    //...

}
Enter fullscreen mode Exit fullscreen mode
Exemplo de indicação de herança no java (herança simples)

A ideia de classe abstrata toma uma formatação diferente e mais específica: as classes são criadas usando abstract class e não podem ser instanciadas porque somente serão progenitoras. A ideia é representar um objeto de maneira abstrata onde obrigatoriamente será herdado por outras classes, ou seja, a criação de atributos e métodos para o objeto pode ser realizada, mas a implementação dos métodos só poderá ser feita nas classes filhas pois ela será apenas um rascunho. Essa é a única diferença de uma classe com herança comum, ela não pode ser instanciada, todavia isso permite mais consistência ao sistema.

public abstract class Person{ // generic class
...
}

public class Consumer extends Person{ // specific class
...
}
Enter fullscreen mode Exit fullscreen mode
Exemplo de herança com classe abstrata

4. POLIMORFISMO

Polimorfismo significa várias formas. Em OOP, ocorre polimorfismo quando um objeto se comporta de várias maneiras ao receber uma informação e isso dependerá do seu tipo de criação, ou seja, nós podemos manipulá-lo de formas diferentes. Em outras palavras, o polimorfismo é quando duas classes têm a mesma descrição de um comportamento, mas as implementações desse comportamento podem ser diferentes.

Na herança, um método da superclasse pode ser reescrito na subclasse e apresentar outro comportamento, um comportamento único para essa classe filha em específico. Isso será possível através da sobreposição/substituição do método (method overriding).

Também é possível realizar polimorfismo sem herança, quando o mesmo método de uma classe executa comportamentos diferentes mas com o mesmo nome do método e isso é possível por meio da sobrecarga de método (method overloading).

Overload

É a criação de mais de um método com mesmo nome, mas com comportamentos diferentes na mesma classe. É chamado de polimorfismo em tempo de compilação ou polimorfismo de sobrecarga e não acontece herança. Nesse polimorfismo nós teremos assinaturas diferentes na mesma classe. Vejamos o exemplo na sintaxe Java:

OBS.: Todo método possui assinatura, ela consiste na quantidade e nos tipos dos parâmetros.

public class Triangle{

  public void draw(){
    System.out.println("Drawing triangle...");
  }

  public void draw(int a, int b, int c){
    System.out.println("Drawing the values of the sides of the triangle...");
    System.out.println("A: "+a);
    System.out.println("B: "+b);
    System.out.println("C: "+c);
  }

}
Enter fullscreen mode Exit fullscreen mode
Exemplo de classe com sobrecarga de método - Métodos com mesmo nome e assinaturas diferentes

Figura 9 - Resultado do exemplo com a classe com sobrecarga de método.

Figura 9 - Resultado do exemplo com a classe com sobrecarga de método.

Override

O overriding acontece nas subclasses. É chamado de polimorfismo em tempo de execução ou polimorfismo de sobreposição, onde o método possui a mesma assinatura em classes diferentes. Vejamos o exemplo na sintaxe Java:

public class Shape {
  public void draw(){
      System.out.println("Drawing shape...");
   }
}

public class Triangle extends Shape{
    @Override
    public void draw(){
      System.out.println("Drawing triangle...");
    }
}

public class Circle extends Shape{
    private int diameter;

    public Circle(int diameter){
        this.diameter = diameter;
    }

    @Override
    public void draw(){
        System.out.println("Drawing circle diameter...");
        System.out.println("Diameter: "+this.diameter); 
    }
}
Enter fullscreen mode Exit fullscreen mode
Exemplo de classe com sobreposição de método-Métodos com mesmo nome e assinaturas iguais.

Figura 10 - Resultado do exemplo com a classe com sobreposição de método.

Figura 10 - Resultado do exemplo com a classe com sobreposição de método.

A classe mãe é Shape e ela contém o método draw que nas classes filhas, draw foi reescrito assumindo formas diferentes de respostas.

As interfaces também são um meio pelo qual você pode obter polimorfismo. Um exemplo disso pode ser como os animais "falam". Um gato pode miar, mas um cachorro late. Ambos os animais podem "falar", mas a implementação do comportamento é diferente. Exemplo:

public class Cat implements IAnimal {
  public void speak() {
    System.out.println("Meoww");
  }
}

public class Dog implements IAnimal {
  public void speak() {
    System.out.println("Au AUu");
  }
}
Enter fullscreen mode Exit fullscreen mode
Polimorfismo com interface

Exemplo do diagrama UML:

Figura 11 - Interação interface e classe no diagrama

Figura 11 - Interação interface e classe no diagrama

VANTAGENS

O paradigma de OOP permite a leitura fácil do código, a organização, a manutenção, a reutilização e a segurança dos dados por meio de encapsulamento e herança. Além disso, o código torna-se muito mais fácil de usar uma vez que tudo é reflexo de entidades do mundo real.

DESVANTAGENS

O código pode se tornar muito confuso se a interpretação dos objetos ou dos módulos não estiverem corretas e ocasionará em redundância ou ineficiência e consequentemente em erros inerentes. Em outras palavras, se a abstração de determinado contexto estiver errada muito provavelmente ocasionará em uma série de falhas desde o desenvolvimento até a entrega final no que se refere a manutenabilidade e a sustentabilidade do sistema, caso não for corrigido.

Por isso, esse paradigma requer mais planejamento, portanto, realizar um design claro das modularizações com antecedência é a receita para evitar desastres. Logo, programas em OOP normalmente exigem um esforço computacional maior do que programas na linguagem funcional.

--- x --- x --- x --- x --- x --- x --- x --- x --- x --- x --- x --- x --- x ---

Se esse conteúdo fez ou não fez sentido para você deixe seu comentário com sugestões e observações.

Obrigada : )

--- x --- x --- x --- x --- x --- x --- x --- x --- x --- x --- x --- x --- x ---

Minha página pessoal, Twitter, Github & Medium

REFERÊNCIAS

University of Alberta Faculty Of Science. Object-Oriented Design.

MIT OPENCOURSEWARE. 8. Object-Oriented Programming . 2017. Disponível em: https://www.youtube.com/watch?v=-DP1i2ZU9gk . Acesso em 11 de ago. 2020.

STUDYTONIGHT. What is Object Oriented Programming (OOPS)? Simple Explanation for Beginners. 2018. Disponível em: https://www.youtube.com/watch?v=xoL6WvCARJY. Acesso em 11 de ago. 2020.

CS DOJO. Introduction to Classes and Objects - Part 1 (Data Structures & Algorithms #3). 2018. Disponível em: https://www.youtube.com/watch?v=8yjkWGRlUmY. Acesso em 11 de ago. 2020.

CS DOJO. Introduction to Classes and Objects - Part 2 (Data Structures & Algorithms #4). 2018. Disponível em: < https://www.youtube.com/watch?v=4dqlSk_RPmI>. Acesso em 11 de ago. 2020.

NETO, Plácido. POO - Programação Orientada a Objetos: Classes em Java. 2014. Disponível em: https://docente.ifrn.edu.br/placidoneto/disciplinas/2014.1/poo/poo-05-construtores. Acesso em 12 de ago. 2020.

.ELLIOT, Eric. The Forgotten History of OOP. 2018. Disponível em: https://medium.com/javascript-scene/the-forgotten-history-of-oop-88d71b9b2d9f#:~:text=%E2%80%9CObject%2DOriented%20Programming%E2%80%9D%20(,his%20Sketchpad%20Thesis%20in%201963. Acesso em 12 de ago. 2020.

WIKIWIKIWEB - WIKI. Alan Kays Definition Of Object Oriented. Disponível em: http://wiki.c2.com/AlanKaysDefinitionOfObjectOriented. Acesso em 12 de ago. 2020.

SCULLY, Ethan. Object-Oriented Programming Languages: A 2020 Guide. 2020. Disponível em: https://careerkarma.com/blog/object-oriented-languages/. Acesso em 12 de ago. 2020.

Top comments (0)