Olá Pessoal, tudo bom?
No artigo de hoje vamos focar um pouco sobre a parte básica de orientação a objetos em Java, definindo conceitos básicos sobre classes, objetos e associações entre classes.
Classes e Objetos
Um aspecto inicial no paradigma da Orientação a Objetos, o qual já é mencionado no próprio nome do paradigma é o objeto. De acordo com BRUCE((Bruce, Kim B. (2002). Foundations of Object-Oriented Languages: Types and Semantics)) a definição de Objeto é:
Objects encapsulate both state and behavior
Objetos encapsulam estado e comportamento em um único lugar
Um conjunto de objetos pode ser de um determinado “tipo”. A esse tipo é dado o nome de Classe. Ainda de acordo com BRUCE((Bruce, Kim B. (2002). Foundations of Object-Oriented Languages: Types and Semantics)) a definição de Classe é:
Are extensible templates for creating objects, providing initial values for instance variables and the bodies for methods. All objects generated from the same classe share de same methods, but contain separate copies of instance variables. New objects can be created from a classe by applying the new operator to the name of the class.
São modelos extensíveis para criar objetos, provendo valores iniciais para instâncias de variáveis e o corpo dos métodos. Todos os objetos gerado pela mesma classe, compartilham dos mesmos métodos, mas contém copias separadas das instâncias das variáveis. Novos objetos podem ser criados a partir da classe aplicando o operador new com o nome da classe.
Para distinguir facilmente entre o conceito de uma classe e um objeto, basta ver a Figura 01:
A partir da figura é possível visualizar que uma classe é a definição da estrutura de algum item do mundo real, sem os valores básicos. Já objetos são a “instanciação”, a criação propriamente dita, de uma classe com valores obtidos a partir de alguma informação do mundo real. Podemos também associar isso com o seguinte pensamento. Quando é mencionada a palavra carro para uma pessoa, o pensamento desta pode variar infinitamente, como uma classe, visto que existem vários modelos e carros. Já quando é mencionada a palavra carro, com um modelo, cor específica e placa, o pensamento desta pessoa, fica limitado ao escopo mencionado, ou seja, um objeto.
Durante a fase de requisitos de um sistema é gerado um texto com as regras negociais e tudo o que o sistema pode realizar. Muitos substantivos identificados nesse texto, podem se tornar uma classe. Uma forma de representar uma classe é através da linguagem UML((UML – Introdução – http://en.wikipedia.org/wiki/Unified_Modeling_Language)), mais especificamente no Diagrama de Classes((Diagrama de Classes – Introdução – http://en.wikipedia.org/wiki/Class_diagram)). A Figura 02 realiza a representação da classe Aeroporto:
Associações entre Classes
Um objeto que representa o mundo real não deve estar sozinho, já que provavelmente ele não está sozinho no mundo real. Dessa forma, vamos pensar sobre a Figura 03:
A linha entre as classes, em um Diagrama de Classes, representa uma associação. Para definir se duas classes estão associadas, é necessário pensar no contexto do projeto e fazer as seguintes perguntas:
- A classe X precisa diretamente da classe Y?
- É necessário a classe X possuir conhecimento da classe Y?
Vamos pensar nisso exemplificando:
Aeroporto – Endereço
- A classe Aeroporto precisa diretamente da classe Endereço?
- É necessário a classe Aeroporto ter conhecimento da classe Endereço?
Para que um objeto Aeroporto seja criado na vida real é necessário que ele possua um endereço para realizar as obras. Logo a resposta para ambas as perguntas é SIM. Dessa forma, existe uma ligação de Aeroporto para Endereço. Mas e o contrário?
Endereço – Aeroporto
- A classe Endereço precisa diretamente da classe Aeroporto?
- É necessário a classe Endereço ter conhecimento da classe Aeroporto?
Para que um objeto Endereço seja criado na vida real não é necessário que ele possua um Aeroporto. Logo a resposta para ambas as pergunta é NÃO. Dessa forma, não existe uma ligação de Endereço para Aeroporto.
A partir desse exemplo é possível perceber que quando existe uma associação entre duas classes A e B, é necessário criar o atributo de uma classe A na classe B, mas isso pode ser dividido em quatro características básicas que compõem uma associação:
- Navegabilidade
- Multiplicidade
- Conectividade
- Obrigatoriedade
Navegabilidade
Podemos pensar como Navegabilidade como um aspecto de Visibilidade. Se uma classe A “enxerga” uma classe B, logo A é navegável para B. Esse conceito de “enxergar”, significa que a classe A contém um atributo com o tipo pertencente a classe B.
1 2 3 4 5 6 7 8 9 10 11 |
public class A { private B b; public B getB(){ return b; } public void setB(B b){ this.b = b; } } |
Partindo desse conceito podemos ter duas formas de navegação básica:
- Unidirecional, onde somente 1 lado “enxerga” o outro lado, representada pela seta aberta, Figura 04:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Aeroporto { private Endereco endereco; //Outros Atributos declarados public Endereco getEndereco(){ return endereco; } public void setEndereco(Endereco endereco){ this.endereco = endereco; } //Outros Métodos declarados } |
- Bidirecional, ambos os lados se “enxergam”, dessa forma a associação não possui nenhuma seta, apenas uma linha, Figura 05:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Rota { private List<Horario> horarios; //Outros Atributos declarados public Horario getHorarios(){ return horarios; } public void setHorarios(List<Horario> horarios){ this.horarios = horarios; } //Outros Métodos declarados } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Horario { private Rota rota; //Outros Atributos declarados public Rota getRota(){ return rota; } public void setRota(Rota rota){ this.rota = rota; } //Outros Métodos declarados } |
Multiplicidade
Representa a quantidade de objetos que um lado da associação “suporta”. Em um diagrama de classes isso é representado por números próximos das associações, como representado na Figura 06:
A leitura de uma associação deve ser feita em um formato de X, ou seja, Um horário possui uma rota. Uma rota possui vários horários. Dessa forma, seria como se fosse quebrada a associação em duas:
Assim como mostrado pelos exemplos, esses números representam os seguintes valores dentro do contexto de classes:
Multiplicidade | Simbologia na UML |
---|---|
Zero ou um | 0..1 |
Zero ou muitos | 0..* ou * |
Apenas um | 1..1 ou 1 |
Um ou muitos | 1..* |
Intervalo específico | Limite Inferior .. Limite Superior (2..5) |
Caso a multiplicidade tenha Limite Superior igual a 1, isso significa que apenas 1 instância da classe Destino deverá ser criada na classe Origem. Por exemplo, na Figura 08 deveremos ter apenas 1 atributo Endereco na declaração da classe Aeroporto. Já em Endereço não temos nada a mais.
Caso a multiplicidade possua um Limite Superior baixo, com valor até 3 objetos, poderá ser criado atributos individuais para cada múltiplo. Por exemplo, uma Rota possui 2 aeroportos, um de origem e um de destino. Logo uma instância de Rota possuirá 2 atributos Aeroportos, um com nome de Origem e outro com o nome de Destino.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class Rota { private Aeroporto origem; private Aeroporto destino; //Outros Atributos declarados public Aeroporto getOrigem(){ return origem; } public void setOrigem(Aeroporto origem){ this.origem = origem; } public Aeroporto getDestino(){ return destino; } public void setDestino(Aeroporto destino){ this.destino = destino; } //Outros Métodos declarados } |
Caso a multiplicidade possua um Limite Superior alto, com valores acima de 3 objetos, deverá ser criado um atributo que seja uma java.util.List da classe requerida. Por exemplo, uma Rota que possui muitos Horários, deverá ser criada uma List<Horario>, representado essa associação.
Conectividade
A conectividade representa a relação da Multiplicidade, mas observando ambos os lados. Para isso temos 4 formas de representar uma conectividade:
- OneToOne – UmParaUm
- OneToMany – UmParaMuitos
- ManyToOne – MuitosParaUm
- ManyToMany – MuitosParaMuitos
Isso é retratado na verdade entre conjuntos de Associações. Por exemplo a associação entre Horário e Rota, partindo de Horário é uma associação ManyToOne, mas o contrário seria OneToMany.
Obrigatoriedade
Por fim ainda existe um último atributo que pode ser representado a partir de associações que é a obrigatoriedade.
Esse atributo indica que a relação deve conter ao menos o número de instâncias indicado pelo limite inferior da multiplicidade da associação, ou seja, o número mínimo na associação. Dessa forma a seguinte associação entre Horário e Rota, indica que ao instanciar um Horário, este deverá conter uma instância válida de Rota. Já o contrário não é obrigatório. Não é necessário possuir instâncias de Horários para criar uma nova Rota. Isso está mais detalhado nos posts sobre construtores de classes que podem ser encontrados aqui (Parte I) e aqui (Parte II).
Finally
Por fim, existem diversas formas de representar as classes de um projeto Java. Cada analista de requisitos pode interpretar um problema de formas diferentes. Assim é necessário que uma equipe de analistas sempre conversem entre si, buscando a melhor maneira de fechar os requisitos de um projeto conjuntamente com a produção dos artefatos de análise, como diagramas de casos de uso, diagramas de classes entre outros.
Por favor envie seus comentários e dúvidas, seja por email ou aqui diretamente.
Obrigado.
Heriberto Pedroso says
Explicação incrível. Obrigado.
Mauda says
Olá Heriberto, tudo bom?
Obrigado pelo feedback!
Precisando estamos por aqui!