Projeto Orientado a Objeto

O termo "projeto" (do inglês design) em desenvolvimento de software é geralmente considerada uma etapa anterior à programação. Na prática, há três conceitos que se sobrepõem e combinam: análise (analysis), programação (programming) e projeto (design).

O termo "orientado a objeto" significa "estar em função de" ou "ser dirigido por". No geral, o projeto orientado a objeto (object-oriented design) utiliza objetos, seus atributos (dados) e comportamentos para descrever ou modelar um domínio.

Gosto dessa visão de "modelar um domínio" porque foi justamente esse o propósito da primeira linguagem de programação orientada a objetos, a Simula 67. O objetivo foi criar uma ferramenta que permitisse simular um domínio por meio de objetos e trocas de mensagens entre eles. Posteriormente, a linguagem de programação Smalltalk 80 aprimorou os conceitos e é considerada, ainda hoje, a única linguagem de programação puramente orientada a objetos.

Antes de falar um pouco mais sobre os conceitos principais da orientação a objetos, veremos brevemente sobre análise, projeto e programação orientada a objetos.

Análise orientada a objetos (OOA, do inglês Object-oriented analysis) é um processo de desenvolvimento de software orientado a objetos no qual se busca observar um problema, sistema ou tarefa e identificar os objetos e as interações entre eles. De outra forma, é identificar o que precisa ser feito. Por exemplo: Um professor precisa corrigir um texto enviado por um aluno. Isso pode ser traduzido em um requisito de software na forma: O sistema deve permitir que um professor possa corrigir um texto enviado por um aluno. Isso é, mais uma vez, o que precisa ser feito. Ainda como parte da análise o objetivo é identificar ações e objetos nesse requisito e poderíamos concluir que:

  • professor é um objeto
  • texto enviado por um aluno é um objeto
  • corrigir é uma ação (do professor)

Projeto orientado a objetos (OOD, do inglês Object-oriented design) é o processo de traduzir um requisito em uma especificação de implementação (o projeto). Geralmente é usado um modelo formal para essa especificação, como a UML (Unified Modeling Language), com o objetivo de descrever como as coisas têm que ser feitas. Considerando o requisito anterior, o objetivo do processo de projeto é descrever o domínio formalmente, na forma de classes e interfaces (também elementos do contexto da orientação a objetos).

Programação orientada a objetos (OOP, do inglês Object-oriented programming) é o processo de utilizar uma linguagem de programação para traduzir o projeto em um programa (software) que faz exatamente o requisitado anteriormente.

Na prática esses processos não são executados de forma exclusiva, mas, geralmente, ao mesmo tempo, com idas e vindas, com revisões e alterações conforme necessário. A partir daqui passamos a conhecer mais de perto os conceitos mais importantes da orientação a objetos antes de descrevê-los usando uma linguagem de programação.

Objetos e classes

Antes de apresentar os conceitos de classes e objetos, e mesmo que tenha dito que não iríamos tratar de linguagem de programação ainda, algo comum em diversas linguagens de programação é que elas representam dados na forma de tipos (tipos de dados). Na verdade, isso é algo anterior à linguagem de programação, sendo uma primitiva da computação, em si. Por exemplo, um número, uma cadeia de caracteres (string) um valor lógico (booleano). Cada tipo de dados é diferente do outro e é utilizado para um propósito. Assim, dizemos que:

  • 1 é um número
  • "abc" é uma string
  • true é um booleano

Na sentença "1 é um número" o "1" é um valor e "número" é o seu tipo. Números e strings são diferentes porque possuem características e propósitos diferentes. Assim, também podemos afirmar que:

  • 1, 2, e 3 são números (do tipo número)
  • "abc", "a" e "c" são strings (do tipo string)
  • true e false são booleanos (do tipo booleano)

Os valores 1, 2 e 3 compartilham semelhanças: são do mesmo tipo. O mesmo vale para os demais valores (que são do mesmo tipo). Coisas que são do mesmo tipo formam grupos ou conjuntos. Podemos afirmar que:

  • o conjunto de números é composto pelos elementos: 1, 2 e 3
  • o conjunto das strings é composto pelos elementos: "abc", "a" e "c"
  • o conjunto dos booleanos é composto pelos elementos: true e false

Com isso em mente podemos afirmar que há uma relação bem próxima entre esses conceitos:

  • tipo e conjunto
  • valor e elemento de conjunto

Agora voltamos para nosso assunto principal.

Por definição um objeto contém atributos (dados) e comportamentos. Eu sei, isso é muito abstrato, mas pense no seguinte: em um determinado domínio, um professor é descrito por meio de atributos:

  • nome
  • CPF
  • número da matrícula funcional
  • data da contratação

Por exemplo, alguns professores seriam representados nesse contexto conforme mostra a tabela a seguir.

nome cpf matrícula funcional data da contratação
Charles F. Xavier 111.111.111-11 1 01/01/1963
Obi-Wan Kenobi 222.222.222-22 2 01/01/1970
Yoda 333.333.333-33 3 01/01/1901

Cada um desses professores é um professor. Isso é lógico. Cada um desses professores seria um elemento do conjunto dos professores. Isso também é lógico. Cada um desses professores é um indivíduo, único, diferente no contexto em questão.

Utilizando orientação a objetos cada um dos professores é um objeto. Isso mesmo. Um objeto é um indivíduo em um contexto. A sentença "Yoda é um professor" está no formato adequado para, em português, indicar que estamos tratando de um objeto. Mas isso não é muito útil se você precisar lidar com pessoas usam formas diferentes de montar frases ou falam outro idioma. Por esse motivo foi criado um idioma padrão para descrever modelos orientados a objeto chamado UML.

UML é uma linguagem gráfica para modelagem ou para criação de especificações de projetos orientados a objeto.

No formato da UML há o seguinte formato para descrever um objeto:

A figura mostra uma caixa (um retângulo) com duas partes:

  • a primeira parte representa a identificação do objeto. O formato objeto : Tipo é interpretado como:
    • objeto é o identificador (nome) do objeto
    • Tipo é o tipo do objeto
  • a segunda parte representa os atributos do objeto, com seus valores, no formato identificador = valor

A segunda parte é opcional e a primeira pode ser representada com variações de formatos:

  • identificador do objeto sem tipo: objeto : ou objeto
  • objeto anônimo com tipo: : Tipo ou Tipo

Considerando que tipo seja Professor, poderíamos representar a tabela anterior usando o Diagrama de objetos da UML ilustrado pela figura a seguir.

Nesse formato é importante notar que:

  • identificadores dos objetos começam com letra minúscula
  • nomes de tipos começam com letra maiúscula
  • valores dos atributos são representados conforme seus tipos (string entre aspas duplas)

Já vimos sobre objetos, então vamos agora tratar sobre o conceito de classe. Conceitualmente classe descreve um objeto e um objeto é uma instância de uma classe. Em outras palavras, objetos são criados a partir de classes. A classe define um conjunto de características (atributos e comportamentos) que são compartilhados por todos os objetos da classe. Voltando ao conceito de tipo de dados, uma classe é um tipo de dados, um agrupador ou um conjunto de objetos. Quando falamos sobre a classe Professor não estamos falando de um professor específico, mas do conceito "professor", o que ele significa dentro de um contexto, sempre.

Conforme o exemplo anterior a classe Professor possui os atributos:

  • nome, do tipo String
  • cpf, do tipo String
  • matricula_funcional, do tipo Número
  • data_de_contratacao, do tipo String

A UML também fornece uma maneira de descrever classes: o Diagrama de classes. Nesse diagrama cada classe é representada no formato indicado na figura a seguir:

A figura mostra um retângulo com três partes:

  • a primeira parte (obrigatória) contém a identificação (nome) da classe (novamente, começando com letra maiúscula)
  • a segunda parte (opcional) contém os atributos, no formato atributo : Tipo
    • atributo é o nome do atributo (começando com letra minúscula)
  • a terceira parte (opcional) contém os métodos (comportamentos -- mais sobre isso daqui a pouco), no formato método(parâmetros) : Tipo:
    • método é o nome do método (começando com letra minúscula)
    • Tipo é o tipo do retorno do método (opcional)
    • parâmetros é a lista dos parâmetros, separados por vírgula, no formato parâmetro : Tipo

Continuando o contexto do exemplo anterior podemos representar a classe Professor da seguinte forma:

Comportamentos são ações

Já sabemos que a orientação a objetos permite representar objetos e classes e que eles possuem atributos, que são os dados que descrevem objetivos específicos. Comportamentos são ações que o objeto pode executar, ou que podem ser executadas tendo o objeto como contexto, e descrevem a maneira como ele se comporta. Na prática, chamamos comportamento de método. Um método (alguns chamam de função) pode:

  • receber uma lista de parâmetros; e
  • retornar algo.

Conceitualmente métodos permitem interações com e entre objetos na forma de mensagens. Um método permite enviar uma mensagem para um objeto, o que pode determinar o que ele tem que fazer. Um método pode modificar um atributo (alterar dados de um objeto) e também representar um processo (como um algoritmo). Para exemplificar, considere a situação a seguir.

Em uma escola as turmas têm vários alunos.

Para representar essa situação considere o diagrama de classes a seguir.

A classe Turma declara o método matricular(), que:

  • aceita um objeto Aluno como parâmetro
  • retorna um Logico para indicar quando a matrícula foi efetivada (True) ou não (False)

Essa situação permite enviar uma mensagem para uma turma com o objetivo de matricular um aluno. Por isso dizemos que métodos representam comportamentos, enquanto atributos representam dados. O diagrama de classes a seguir apresenta outro modelo.

O modelo indica o seguinte:

  • a classe Escola declara dois atributos:
    • turmas: representa a lista de turmas
    • alunos: representa a lista de alunos (estudantes) da escola
  • a classe Turma declara:
    • o atributo alunos: representa a lista de alunos (estudantes) da turma
    • o método matricular(aluno: Aluno): Lógico: permite matricular um aluno na turma
  • a classe Aluno declara dois métodos:
    • matricular(): permite matricular um aluno na escola. Nesse caso, deve ocorrer uma interação entre dois objetos, um do tipo Escola e outro do tipo Aluno, para que o aluno seja inserido na lista de alunos da escola (atributo Escola.alunos)
    • matricular_em_turma(turma: Turma): permite matricular um aluno na turma. Nesse caso, deve ocorrer uma interação entre dois objetos, um do tipo Turma e outro do tipo Aluno, para que o aluno possa ser inserido na lista de alunos da turma (atributo Turma.alunos).

Diagrama de Classes e Diagrama de Objetos

Ainda no contexto de uma sala de aula poderíamos considerar o seguinte:

  • Um professor é descrito pelos atributos: nome, cpf, matrícula funcional e data de contratação
  • Um aluno é descrito pelos atributos: nome, cpf, número de matrícula e turma (aluno está matriculado em uma turma)
  • Uma turma é descrita pelos atributos: número, disciplina e professor (turma tem um professor)

Além de três classes há duas relações entre elas (destacando):

  • aluno está matriculado em turma
  • turma tem professor

A UML também permite representar relações entre classes. Para demonstrar as relações entre as classes Aluno, Turma e Professor poderíamos utilizar o Diagrama de classes a seguir.

A relação entre duas classes tem um nome (rótulo da seta) e uma seta (direcionada, por padrão). Na classe Aluno o atributo turma é do tipo Turma. Essa é uma observação importante porque ela explica o motivo de a seta da relação está matriculado em ser direcionada (partindo de Aluno e chegando em Turma). Da mesma, na classe Turma o atributo professor é do tipo Professor e isso explica a relação tem (entre as classes Turma e Professor).

Um modelo de objetos nesse contexto poderia ser representado pelo Diagrama de objetos a seguir.

Os objetos são:

  • do tipo Aluno: luke e anakin
  • do tipo Turma: t1 e t2
  • do tipo Professor: obiwan

As relações entre eles demonstram:

  • turma t1 tem professor obiwan
  • anakin está matriculado na turma t1
  • turma t2 tem professor obiwan
  • luke está matriculado na turma t2

Em termos de modelagem (atividade parte dos processos de análise e projeto) a orientação a objetos fornece recursos bastante suficientes para descrever os mais diversos modelos.

Abstração e encapsulamento

Abstração e encapsulamento são dois conceitos importantes em projeto orientado a objeto. Conceitualmente, afirmamos que Abstração é o processo de encapsular informação (atributos e métodos) em dois tipos de interfaces: a interface pública e a interface privada.

A interface pública declara atributos e métodos que podem ser utilizados por outros objetos livremente, enquanto a interface privada declara atributos e métodos que só podem ser utilizados internamente, pelo próprio objeto.

Para esclarecer estes conceitos considere a situação a seguir.

Um controle remoto de um televisor possui botões que, ao serem pressionados, executam determinadas ações do televisor de forma remota, como ligar, desligar, aumentar e diminuir o volume do som e mudar o canal.

O conjunto de botões do controle remoto representam a sua interface pública. Eles estão visíveis e podem ser livremente utilizados (pressionados). O importante é que essa interface não deve passar por alterações constantes (como mudança de cores ou posicionamento dos botões), já que isso poderia comprometer a experiência do usuário.

Entretanto, o controle remoto, por ser uma caixa, está ocultando determinados componentes eletrônicos internos, que não podem ser utilizados diretamente. Isso representa a sua interface privada.

Em UML diferenciamos esses dois conceitos utilizando uma indicação de visibilidade do atributo ou do método, como mostra a figura a seguir.

A classe Turma possui a seguinte estrutura:

Atributo/Método Visibilidade Descrição
disciplina privado indica o nome da disciplina da turma
ano privado indica o ano da turma
alunos privado indica a lista de alunos da turma
disciplina() público retorna o nome da disciplina da turma
ano() público retorna o ano da turma
matricular() público matricula um aluno na turma
inserir_aluno_na_lista() privado insere um aluno na lista de alunos

No Diagrama de classe o atributo ou método privado tem uma indicação de um quadrado vermelho antes do seu nome (não-preenchido para atributos e preenchido em vermelho para métodos), enquanto o atributo ou método público é indicado por um círculo verde (não-preenchido para atributos e preenchido em verde para métodos).

Composição e Agregação

Como demonstrou um exemplo anterior, uma turma tem alunos e essa definição, em um diagrama de classes, é representada por meio de uma seta, uma ligação entre duas classes (por exemplo, Turma e Aluno). Entretanto, há uma maneira de ser mais específico sobre esta ligação entre as duas classes, utilizando os conceitos de Composição e Agregação.

Uma Composição é uma relação entre dois objetos para criar um só, representando um relacionamento do tipo "todo/parte". Para exemplificar, considere o seguinte:

Em uma escola uma turma é composta por informações próprias (disciplina e ano), professor e alunos. Uma turma não existe sem que haja um professor, mas não precisa ter alunos.

Como representar isso utilizando UML? Utilizando composição para demonstrar que uma turma tem como parte um professor. Veja a figura a seguir.

As classes Turma e Professor estão relacionadas entre si e indicam que o professor faz parte da turma. Em outras palavras, é necessário que haja um professor para que a turma exista. Esse condicional, essa restrição é representada pela composição. Em termos do Diagrama de classes, esse relacionamento é representado por um losango preenchido do lado "todo" da relação: turma é o "todo", enquanto professor é "parte".

Além disso o Diagrama de classes demonstra como representar a cardinalidade. Os dois lados da linha que liga Turma e Professor possuem uma indicação numérica que indica que:

  • Turma tem apenas um professor (o número 1 próximo de Professor indica isso)
  • Professor pode estar em uma ou mais turmas (a representação 1..* próxima de Turma indica isso)

Em termos de objetos o Diagrama de objetos a seguir ilustra essa situação.

Em termos de sequência, primeiro seria necessário criar o objeto jackson e, depois, o objeto lpoo, já que demonstram composição.

Uma Agregação também é uma composição, mas com uma característica diferente: os objetos existem independemente um do outro. Para exemplificar, vamos usar o mesmo cenário anterior, com foco na relação entre turmas e alunos. O cenário indica que a turma não precisa ter alunos para existir e isso é representado pelo Diagrama de classes a seguir.

As classes Turma e Aluno estão relacionadas e indicam que os alunos fazem parte da turma. Esse relacionamento é representado pela linha que liga as duas classes com um losango não preenchido do lado de Turma. A cardinalidade é importante para indicar que:

  • Turma tem zero ou mais alunos (o símbolo * próximo de Aluno indica isso)
  • Aluno pode estar em apenas uma turma (o número 1 proximo de Turma indica isso)

O símbolo * significa "zero ou mais"

O Diagrama de objetos a seguir ilustra essa situação.

Para concluir, afirmamos o seguinte:

Toda agregação é uma composição, mas nem toda composição é uma agregação.

Herança

Até agora foram apresentados três tipos de relacionamentos entre objetos: associação, composição e agregação. Entra agora um dos principais conceitos de Projeto Orientado a Objeto: herança.

Herança é um relacionamento é-um ou é-um-tipo-de. Por meio desse recurso uma classe pode herdar atributos e comportamento de outra classe. Vamos considerar um exemplo prático para demonstrar o conceito: na seção anterior, vimos que as classes Aluno e Professor tinham um atributo com mesmo nome e tipo (nome: String). Isso é uma repetição que podemos evitar usando herança, pensando primeiro em uma classe mais geral, ou que generaliza Aluno e Professor, e permite representar esses fatos:

  • Aluno é um <classe mais geral> ou Aluno é um tipo de <classe mais geral>
  • Professor é um <classe mais geral> ou Professor é um tipo de <classe mais geral>

Para isso, vamos usar herança. Veja a figura:

Nos termos da UML o diagrama de classe representa herança por meio de uma linha entre duas classes e um triângulo não preenchido do lado da classe mais geral. Quando falo sobre a classe Pessoa ser mais geral também quero dizer, de forma complementar, que Aluno e Professor são especializações de Pessoa. Generalização e especialização são os processos mentais que o projetista usa para modelar as relações de herança entre classes.

Há outros nomes, sinônimos no contexto de herança:

  • classe mais geral pode ser chamada de classe pai ou superclasse; e
  • classe específica pode ser chamada de classe filha ou subclasse.

Daqui em diante vamos usar os termos superclasse e subclasse. No exemplo anterior teríamos:

  • Pessoa é superclasse de Aluno e Professor
  • Aluno é subclasse de Pessoa
  • Professor é subclasse de Pessoa

results matching ""

    No results matching ""