Composição
Situação em que uma classe seja composta por outros objectos e:
- faça a gestão do ciclo de vida dos mesmos
- faça a criação dos objectos internamente
- não os receba por parâmetros já criados

public class Turma {
private String designação;
private Aluno[] alunos; // Composição
private int capacidade;
//variaveis internas para controlo do numero de alunos
private int ocupacao;
//se não for especificado o tamanho da turma usa-se esta constante
private static final int capacidade_inicial = 20;
}
- getAlunos é declarado como auxiliar e privado
/**
* Método privado(auxiliar)
* possível problema de encapsulamento ao partilhar o endereço do array
*
* @return Array com os objectos do tipo Aluno
*/
prrivate Aluno[] getAlunos(){
return this.alunos
}
- Quem cria a instância de Aluno é a classe Turma
/**
* Este método assume que se vreifica perviamente se ainda existe espaço para
* mais um aluno na turma.
* Em futuras versões desta classe poderemos fazer internamente a gestão das
* situações de erro. Neste momento assume-se que a pré condição é verdadeira.
*/
public void insereAluno(String numer, int nota, String nome, string cruso){
this.alunos[this.ocupaçao] = new Aluno(numero, nota, nome, curso);
this.ocupacao++;
}
/**
* Método que insere um aluno na turma, mas recebe já uma isntãncia da classe
* Aluno
* Como forma de garantir o encapsulamento cria-se uma cópia do objecto recebido
*
*/
public void insereAluno(Aluno umAluno){
this.alunos[this.ocupaçao] = new Aluno(umAluno);
this.ocupacao++;
}
- Como foi decidido, na fase de concepção, que a estratégia de associação previa uma composição então é necessário explicitamente clonar o objecto.

Clone
- Criação de uma cópia do objecto a quem é enviado
- x.clone() != x
- x.clone().getClass() == x.getClass()
- A utilização de clone() permite que seja possível preservarmos o encapsulamento dos objectos, desde que:
->seja feita uma cópia dos objectos à entrada dos métodos
->seja devolvida uma cópia dos objectos e não o apontador para os mesmos
/**
* Implementação do método de cloangem de um Aluno
*
* @return objecto de tipo Aluno
*/
public ALuno clone(){
return Aluno(this);
}
- Duas abordagens:
-> Shallow Clone: cópia parcial que deixa endereços partilhados (cria as estruturas de dados mas partilha os conteúdos)
-> Deep Clone: cópia em que nenhum objecto partilha endereços com outro
Objetos Imutáveis que não precisam ser clonados: -> String -> Integer -> Float -> (...)
- O método clone() existente nas classes Java é sempre shallow, e devolve sempre um Object (se usado, é necessário fazer cast) consistente
Equals
- alunos[i] == a -> compara apontadores se a clone de alunos[i] então dá false
- (alunos[i]).getNumero() == a.getNumero() -> assume demasiado sobre como se comparam alunos.
- Dois objectos são iguais se forem o mesmo, se tiverem o mesmo apontador ou as mesmas variáveis de instância.
Regras para usar equals: -> reflexivo -> x.equals(x) == true -> simétrico -> Se x.equals(y) == true então y.equals(x) == true -> transitiva -> x.equals(y) == true && y.equals(z) == true então x.equals(z) == true -> consistente -> sucessivas repetições de x.equals(y) ou y.equals(x) dá sempre o mesmo valor
- Para valores nulos, a comparação com x, não nulo, dá como resultado false.
Caso não se implemente o método equals por omissão o java faz:
public boolean equals(Object object){
return this == object;
}
Template típico de um método equals:
public boolean equals(Object o){
if (this == 0)
return true;
if((o == null) || (this.getClass() != o.getClass()))
return false;
<CLASSE> m = (<CLASSE>) o;
return (<condições de igualdade>);
}
Exemplo classe Aluno:
/**
* Implementação do método de igualdade entre dois Aluno
* Redefinição do método equals de Object
*
* @param umAluno aluno é comparado com receptor
* @return booleano true ou false
*/
public boolean equals(Object o){
if (this == 0)
return true;
if((o == null) || (this.getClass() != o.getClass()))
return false;
Aluno umAluno = (Aluno) o;
return (this.nome.equals(umAluno.getNome())
&& this.nota == umAluno.getNota()
&& this.numero.equals(umAluno.getNumero())
&& this.curso.equals(umAluno.getCurso())
);
}
toString
-
Caso não seja implementado a resposta é: -> getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
-
Todas as classes devem implementar este método
/**
* Implementação do método toString
* comum na maioria das classes Java
*
* @return uma string com a informação textual do objecto aluno
*/
public String toString(){
return("Numero" + this.numero + "Numero" + this.nome + "Nota:" this.nota);
}
- Strings são objectos imutáveis, logo não crescem, o que as torna muito ineficientes
- Para tornar a construção de Strings mais simples (e legível) pode recorrer-se à utilização da classe StringBuilder
/**
* Implementação do método toString
* comum na maioria das classes Java
*
* @return uma string com a informação textual do objecto aluno
*/
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("Numero: ");
sb.append(this.numero+"\n");
sb.append("Nome: ");
sb.append(this.nome+"\n");
sb.append("Nota: ");
sb.append(this.nota+"\n");
return sb.toString();
}
Agregação
- Neste Caso as instâncias de Aluno já não são internas à Turma - partilha-se o apontador

Sumário
-
Composição: -> faz-se cópia (clone) dos objectos quando são guardados internamente -> devolve-se sempre uma cópia dos objectos e,caso seja necessário, da estrutura de dados que os guarda
-
Agregação: -> guarda-se internamente o apontador dos objectos passados como parâmetro -> devolve-se sempre o apontador dos objectos e, caso seja solicitado, uma cópia da estrutura da dados que os guarda.

- Quando o diagrama de classes não explicitar se a associação é de composição
Variáveis e Métodos de Classe
- as variáveis de classe servem para guardar informação global a todas as instâncias
- podem também ser utilizadas para guardar constantes que são utilizadas pelos diversos objectos instância
- os métodos de classe fazem o acesso às variáveis de classe
- os métodos de classe são sempre acessíveis às instâncias, mas métodos de classe não tem acesso aos métodos de instância
- se uma classe possui variáveis de classe o acesso a essas variáveis deverá ser feito através dos métodos de classe
- declaram métodos e variáveis de classe -> utilizando o prefixo static
- seja uma classe Factura, que modela de forma muito simples uma factura
-> queremos representar a informação que permitirá ao criar uma factura ajustar o valor ao imposto que na altura está em vigor.
->terá de ser uma definição global a todas as instâncias
public class Factura{
//variáveis de instância
private String nomeEmpresa;
private String nif;
private String descricaoDespesa;
private LocalDate dataFact;
private double valorFact;
private double valorApgar; //pelo cliente, depois de aplicando o imposto
// a taxa de imposto é definida globalmente para todos
// as facturas e na altura da emissão deve utilizar-se
// a taxa de imposto actual.
poublic static double taxaImposto;
public static double getTaxaImposto(){
return taxaImposto;
}
public static void setTaxaImposto(double tx){
taxaImposto = tx;
}
}