Cursos: Análise, Ciência da Computação e Sistemas de Informação Programação I - Prof. Aníbal Notas de aula 5 ASSOCIAÇÃO ENTRE CLASSES O objetivo deste texto é rever, um pouco mais detidamente, o relacionamento de associação entre classes. Sempre que um atributo de uma classe não é de tipo primitivo, temos uma associação desta classe com alguma outra. O primeiro caso deste que vimos foi com os atributos do tipo String, que, como já sabemos, não é um tipo primitivo. Todo string é um objeto da classe String de Java. Vamos agora ver exemplos de associações entre classes que nós mesmos construímos. Suponhamos uma classe com dois atributos apenas, código e datadenascimento. O código é um número inteiro que identifica o cliente, portanto, um tipo primitivo (int), mas a data de nascimento é composta de três valores inteiros (dia, mês e ano). Logo, nosso atributo de data deveria ser desmembrado em três atributos inteiros. É mais conveniente, neste caso, criarmos uma classe com os três atributos, e dar este tipo ao atributo datadenascimento. Por outro lado, a classe pode implementar uma série de funcionalidades através de seus métodos, como retornar a data em formatos diversos (ex: 10 de agosto de 2006, 10/08/2006, 10-08-06, etc.). Uma classe como esta certamente terá muita utilidade para diversas outras. public class { private int dia; private int mes; private int ano; public (int d, int m, int a){//constrói uma data public String databarra(){//devolve data na forma dd/mm/aaaa public int datainvertida(){//devolve data int na forma aaaammdd public void le(){//lê do teclado uma data public String dataextenso()//devolve data por extenso dd de mmmmmm de aaaa public int getdia(){//devolve o dia public int getmes(){//devolve o mês public int getano(){//devolve o ano public String obtemmesextenso()//devolve o mês por extenso public class { private int codigo; private datadenascimento; //associa a classe à classe.. Na modelagem, usando a linguagem UML, a associação é indicada por uma linha cheia com uma seta aberta direcionada da classe que possui o atributo para a classe que dá tipo a este atributo. Em nosso exemplo, teríamos: A seta indica que um objeto cliente conhece um objeto data, mas um objeto data não conhece o objeto cliente. Programação I - Prof. Aníbal - Notas de aula 5 1
O significado da associação Uma associação (binária) é um relacionamento estrutural entre duas classes, especificando que os objetos de uma classe estão conectados a objetos de outra. No caso apresentado, cada objeto cliente estará ligado a um objeto data. Por exemplo, se o cliente de código 123 nasceu no Natal de 1980, podemos representar o objeto correspondente assim: codigo 123 datadenascimento dia 25 mes 12 ano 1980 Dizemos que se pode navegar do cliente para a data, mas o inverso não é garantido. Também pode-se dizer que o objeto data é visível pelo objeto cliente, mas o inverso não pode ser afirmado. Relação entre as existências dos dois objetos Se a existência do objeto data é dependente ou não da do objeto cliente, isto varia conforme a aplicação do mundo real. Vamos examinar aqui algumas possibilidades observando parte do código Java da classe : public class { private int codigo; private datadenascimento; public (int umcodigo, int umdia, int ummes, int umano){ //Constr. 1 datadenascimento = new (umdia, ummes, umano); public (int umcodigo, uma){ // Construtor 2 datadenascimento = uma; public (int umcodigo){ // Construtor 3 datadenascimento = null;. public void setdenascimento(int umdia, int ummes, int umano){ datadenascimento = new (umdia, ummes, umano); public void setdenascimento( uma){ datadenascimento = uma;. Usando o construtor 1, o objeto data é instanciado durante a construção do objeto cliente, indicando uma forte dependência da data em relação ao dono desta data. Ex: c1 = new (123, 25, 12, 1980); Programação I - Prof. Aníbal - Notas de aula 5 2
Para chamar o construtor 2, é necessário antes instanciar um objeto data que é passado como argumento. Isto indica uma maior independência entre os dois objetos, pois o objeto data pode ter sido instanciado (e, até, ter sido usado para outras finalidades) muito antes da instanciação do cliente. Ex: DeNascimento dt1 = new DeNascimento(7, 9, 1967); c2 = new (456, dt1); O uso do construtor 3 também mostra certa independência entre a existência dos dois objetos, pois ele permite instanciar um cliente e deixá-lo temporariamente (ou até mesmo definitivamente) sem uma data de nascimento. Neste caso, porém, fica evidente a necessidade de pelo menos um dos métodos sobrecarregados setdenascimento para permitir a introdução da referida data mais tarde, após a instanciação do objeto cliente. Ex: c3 = new (789);//constrói cliente sem data de nascimento DeNascimento dt2 = new DeNascimento(1, 4, 1943); c3.setdenascimento(dt2); //introduz a data de nascimento mais tarde c3.setdenascimento(1, 4, 1943); //outra forma de fazer a mesma coisa Usando o atributo objeto O atributo datadenascimento é uma referência a um objeto. Logo, através desta referência podemos chamar os diversos métodos da classe a partir dos métodos da classe. Por exemplo, um método que exibe os dados do cliente na tela pode ser: public void exibedados(){ System.out.println("Código do cliente: " + codigo); System.out.println(" de nascimento: " + datadenascimento.databarra()); Observe que, obviamente, a classe não tem acesso direto aos atributos da classe, pois estes são private. O acesso é feito sempre através da interface pública da classe (os métodos, que devem ser públicos, naturalmente). Assim, dentro da classe a chamada datadenascimento.dia causaria um erro de compilação. Exercício 5.1. Dada a classe abaixo: public class Endereco{ private String ruanumero; private String cidade; private String uf; private String cep; public endereco(string rn, String cd, String u, String cp){ //constrói um endereço public void setruanumero(string novoruanum){ public void setcidade(string novacidade){ public void setuf(string novauf){ public void setcep(string novocep){ public String getruanumero(){//devolve o valor de ruanumero public String getcidade(){//devolve nome da cidade public String getuf(){//devolve a Unidade da Federação public String getcep(){//devolve o valor do C.E.P. acrescente à classe um atributo de nome endereco, e altere ou acrescente o que for necessário em termos de métodos e construtores, para permitir inserir endereço dos clientes, junto com o seu cadastramento ou mais tarde. Programação I - Prof. Aníbal - Notas de aula 5 3
Outro exemplo Apresentamos um outro exemplo de associação. Supondo que um banco não admita contas-correntes conjuntas, e aproveitando as classes e já vistas neste capítulo, podemos ter: public class ContaCorrente{ private int numero; private cliente; private datadeabertura; private double saldo;.. O diagrama abaixo modela a situação proposta: ContaCorrente Observe as navegações possíveis. Um objeto conta-corrente pode acessar o objeto cliente, mas, este não pode acessar a conta-corrente da qual ele é o titular. Supondo que no referido banco um cliente só possa ter uma conta-corrente (o que, aliás, já foi norma válida no Brasil em algum momento), poderíamos dotar a classe de um atributo para indicar a sua conta: private ContaCorrente conta; Então, a linha de associação entre ContaCorrente e passaria a ser bidirecional, indicando-se com setas em ambas as extremidades ou simplificando-se para uma linha sem setas, que é a notação UML mais aplicada para este caso. ContaCorrente Diferença entre associação e dependência Quando uma classe, em um ou mais de seus métodos, utiliza um objeto de outra classe, dizemos que a primeira classe depende da segunda. Existe, aqui, portanto, um relacionamento de Dependência. É o que ocorre, por exemplo, numa classe de teste, quando instancia objeto e depois chama métodos da classe testada. Outro exemplo é o uso da classe Teclado. Quando uma classe qualquer usa a classe Teclado, ela instancia um teclado para poder usar os métodos de leitura de dados. Então, a classe depende da classe Teclado. O relacionamento deste tipo é representado, em UML, por uma linha tracejada com uma seta aberta, apontando a classe de que a outra depende. Exemplo: Programação I - Prof. Aníbal - Notas de aula 5 4
Testa Teclado O diagrama de classes UML acima mostra relacionamentos de associação e de dependência. É fácil evitar confusão entre os dois tipos: só existe associação quando uma classe tem atributo cujo tipo é a outra classe. A UML prevê quatro categorias de relacionamentos entre classes: além das duas vistas neste texto (Associação e Dependência), existe a Generalização (também chamada de Especialização), que é implementada pelo mecanismo de Herança (assunto do capítulo 7), e a Realização, que não será estudada em Programação I. A Agregação é um tipo especial de associação e a Composição é um tipo especial de Agregação. Estes dois tipos especiais de associação são tratados, por muitos autores, como conceitos avançados de modelagem e não serão estudados aqui. Exercícios 1. Dado o modelo UML abaixo, marque V ou F para cada sentença seguinte: Empresa Empregado ( ) A classe Empresa tem um atributo do tipo Empregado, mas a classe Empregado não tem atributo do tipo Empresa. ( ) Todo objeto empregado sabe qual a empresa que o emprega, e todo objeto empresa sabe quais são seus empregados. ( ) A classe Empresa não tem atributo do tipo Empregado, ela apenas instancia objetos do tipo Empregado. ( ) Na classe Empregado existe algum atributo do tipo Empresa. 2. Num sistema hospitalar, temos as classes Paciente, Médico, e Endereco. Todo paciente tem uma data de nascimento, um endereço e um médico de sua preferência. Cada médico tem sua data de nascimento, sua data de admissão no hospital e um endereço. Mostre as associações existentes entre as classes. 3. Desenhe as associações que existem entre as classes Pessoa, Carro, String e, sabendo que os atributos de Pessoa são: nome, data de nascimento, veículo de sua propriedade e valor do seu salário. A classe Carro tem os atributos: placas, cor, modelo, data de fabricação e proprietário atual. A classe tem atributos dia, mês e ano. Programação I - Prof. Aníbal - Notas de aula 5 5