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 BRUCE1)Bruce, Kim B. (2002). Foundations of Object-Oriented Languages: Types and Semantics a definição de Objeto é:
Um conjunto de objetos pode ser de um determinado "tipo". A esse tipo é dado o nome de Classe. Ainda de acordo com BRUCE2)Bruce, Kim B. (2002). Foundations of Object-Oriented Languages: Types and Semantics a definição de Classe é:
Para distinguir facilmente entre o conceito de uma classe e um objeto, basta ver a Figura 01:
Figura 01 – Distinção entre classe e objeto
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 UML3)UML – Introdução – http://en.wikipedia.org/wiki/Unified_Modeling_Language, mais especificamente no Diagrama de Classes4)Diagrama de Classes – Introdução – http://en.wikipedia.org/wiki/Class_diagram. A Figura 02 realiza a representação da classe Aeroporto:
Figura 02 – Representação de uma classe UML
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:
Figura 03 – Associação entre Aeroporto e Endereco através da UML
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:
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.
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:
Figura 04 – Associação entre Aeroporto e Endereco através da UML
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 }
//Outros Atributos declarados
public Endereco getEndereco(){
public void setEndereco(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:
Figura 05 -Representação de uma associação bidirecional
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 }
public class Rota {
private List<Horario> horarios;
public Horario getHorarios(){
public void setHorarios(List<Horario> horarios){
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 }
private Rota rota;
public Rota getRota(){
return rota;
public void setRota(Rota rota){
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:
Figura 06 -Representação de uma associação com multiplicidade
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:
Figura 07 – Associação Bidirecional entre Horário e Rota quebrada em duas unidirecionais.
Assim como mostrado pelos exemplos, esses números representam os seguintes valores dentro do contexto de classes:
Zero ou muitos 0..* ou *
Apenas um 1..1 ou 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.
Figura 08 – Representação de uma associação entre classes com Limite Superior igual a 1 em UML
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.
Figura 09 – Associação Unidirecional entre Rota e Aeroporto
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 }
private Aeroporto origem;
private Aeroporto destino;
public Aeroporto getOrigem(){
public void setOrigem(Aeroporto origem){
public Aeroporto getDestino(){
public void setDestino(Aeroporto destino){
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.
Figura 10 -Representação da associação Rota e Horário
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.
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).
Figura 11 -Representação da obrigatoriedade entre Rota e Horário
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.