E N D
Herança • O que é herança? • Herdar é derivar características de gerações precedentes. No mundo da Programação Orientada a Objetos, o termo é associado com uma das formas de reutilização de software. Através da herança, novas classes podem ser derivadas das classes existentes. A nova classe herda propriedades e métodos da classe base. A nova classe também pode adicionar suas próprias propriedades e métodos
Herança • Para que serve a herança?Considere a criação de uma classe ClasseB em Java.Que métodos estão disponíveis através de uma referência para a ClasseB (isto é, um objeto)?
Herança • Suponha agora que a classe ClasseB herda de ClasseAQue métodos estão agora disponíveis para uma referência da ClasseB (um objeto) ?
Herança • Poderoso mecanismo para o reaproveitamento de código • O objeto objB tem agora disponíveis os métodos da ClasseA sem ser necessário reescrevê-los na ClasseB • Um objeto da ClasseB também é um objeto da ClasseA. • Facilita a manutenção do código: Os métodos não são replicados. Se for necessário alterar o código do método m3, basta alterá-lo em ClasseA. • ClasseB pode "recusar" parte da herança reimplementando os métodos herdados
Herança O método m3 agora disponível para objB é aquele implementado em ClasseB
Herança • Várias subclasses podem herdar da mesma superclasse
Herança • Em Java, não é permitido herdar de mais de uma classe ERRADO!!!!
Herança • A hierarquia de herança pode ter vários níveis
Herança • Que métodos estão agora disponíveis para uma instância de ClasseC?
Herança • A Herança também pode surgir a partir da refatoração de classes existentes de modo a eliminar a duplicação de código Grande quantidade de atributos e métodos duplicados...
Herança • Refatoração Superclasse(características comuns) Subclasses(características específicas)
Herança • O mecanismo de herança pode ser melhor entendido através do seguinte exemplo:
Herança • A classe ContaBancaria tem quatro atributos: • nome: armazena o nome do cliente • cpf: armazena o número do CPF do cliente • numeroConta: armazena o número da conta do cliente • saldo: armazena o saldo da conta • Os métodos depositar e sacar são usados para fazer um depósito ou retirada da conta bancária. • A classe ContaBancária, sozinha, não é suficiente para realizar todas as transações bancárias. Existem geralmente dois tipos de contas: a conta corrente e a conta de investimentos
Herança • Vamos derivar portanto duas subclasses que herdam da superclasse ContaCorrente
Herança As subclasses ContaInvestimento e ContaCorrente herdam os atributos e métodos da classe ContaBancaria
Herança • Agora é possível fazer: Apesar do método depositar não ter sido definido para a classe ContaCorrente, ele está disponível devido ao mecanismo de herança
Composição • A classe contém referências para objetos de outras classes • Estas referências são também atributos da classe • Uma maneira alternativa de estender a funcionalidade de uma classe agregando funcionalidades de outras classes • Herança vs. ComposiçãoÉ UM vs. TEM UM
Composição • O mecanismo de herança nem sempre é apropriado • Java não tem herança múltipla • Estender funcionalidade através de herança pode não ser "natural": • Uma conta de investimento é uma conta bancária • Uma conta de investimento não é uma classe DecimalFormat!
Composição • Considere a seguinte situação:
Composição • Considere agora que é preciso estender a funcionalidade da classe CA oferecendo em sua interface também os métodos m3( ) e m4( )
Composição • 1a solução: Implementar os métodos m3( ) e m4( ) na classe CA. • Desvantagem: • duplicação de métodos dificulta a manutenção do software
Composição • 2asolução: Herança • Desvantagens: • Conceitualmente, a classe CA pode não SER uma classe CB • Java não suporta herança múltipla. E se fosse necessário oferecer os serviços m5() e m6() de uma classe CC?
Composição • 3a solução: Composição
Composição • Que serviços estão disponíveis para uma referência da classe CA?
Composição • No entanto, é possível fazer: • Observe a utilização dos métodos m3 e m4 através de uma referência para a classe CB
Composição • Esse processo é também conhecido por delegação: a classe CA delega à classe CB a execução dos serviços m3 e m4 • Observe que o atributo b na classe A é público. Diz-se então que a delegação é pública, isto é, ela é visível para os clientes da classe • Um cliente da classe CA, para usar os métodos m3 e m4, deve estar ciente da delegação e fazer: obj.b.m3();
Composição • É possível tornar a delegação privada:
Composição • Oferecer os serviços m3 e m4 na classe CA não significa, neste caso, duplicar código. Os métodos m3 e m4 em CA são apenas uma fachada para os métodos m3 e m4 em CB
Composição • Que serviços estão agora disponíveis para uma referência da classe CA? • Observe que, agora, o cliente da classe não conhece a delegação: para ele tudo se passa como se os métodos m3 e m4 fossem implementados em CA
Composição • Um exemplo no próprio Delphi: A classe System • Para imprimir uma String no console faz-se: System.out.println("Alo Mundo!"); método da classe PrintStream delegação
Composição • Um serviço oferecido por uma classe pode não ser exatamente uma fachada para a classe delegada, mas uma combinação de serviços oferecidos por esta. • Observe atentamente o código a seguir:
public class Data { privateint dia; privateint mes; privateint ano; public Data(int d, int m, int a) { dia = d; mes = m; ano = a; } public Data(String strData) { dia = Integer.parseInt(strData.substring(0, 2)); mes = Integer.parseInt(strData.substring(3, 5)); ano = Integer.parseInt(strData.substring(6)); } public String toString() { // imprime a data no formato dd/mm/aaaa DecimalFormat df = new DecimalFormat("00"); return df.format(dia) + "/" + df.format(mes) + "/" + ano; } } monta uma String no formato dd/mm/aaaa df.format()se o campo tem apenas um dígito preenche com um zero à esquerda
publicclass Empregado { private Data admissao; private Data nascimento; private String nome; public Empregado(Data admissao, Data nascimento, String nome) { this.admissao = admissao; this.nascimento = nascimento; this.nome = nome; } public String toString() { return "nome: " + nome + "\nnascimento: " + nascimento.toString() + "\nadmissao: " + admissao.toString(); } } monta uma String contendo o nome, data de nascimento e data de admissão do Empregado
publicclass Teste { publicstaticvoid main(String args[]) { String aux = EasyIn.getString("Data do aniversario[dd/mm/aaaa]: "); Data data1 = new Data(aux); aux = EasyIn.getString("Data da admissao[dd/mm/aaaa]: "); Data data2 = new Data(aux); aux = EasyIn.getString("nome: "); Empregado emp = new Empregado(data2, data1, aux); System.out.println(emp.toString()); } } lê uma String contendo a data de aniversário e usa o método substring para separar o dia, o mês e o ano o mesmo para a data de admissão instancia um objeto Empregado invoca o método toString da classe Empregado. Este, por sua vez, usa o método toString da classe Data
Data do aniversario[dd/mm/aaaa]: 09/03/1974 Data da admissao[dd/mm/aaaa]: 20/04/1994 nome: Rafael Marques nome: Rafael Marques nascimento: 09/03/1974 admissao: 20/04/1994 Process finished with exit code 0
Composição • Vamos repetir o mesmo exemplo, dessa vez usando uma interface gráfica com o usuário • Observe a utilização das mesmas classes de negócio (Empregado e Data)
class Data { privateint dia; privateint mes; privateint ano; public Data(int d, int m, int a) { dia = d; mes = m; ano = a; } public Data(String strData) { dia = Integer.parseInt(strData.substring(0, 2)); mes = Integer.parseInt(strData.substring(3, 5)); ano = Integer.parseInt(strData.substring(6)); } public String toString() { // imprime a data no formato dd/mm/aaaa DecimalFormat df = new DecimalFormat("00"); return df.format(dia) + "/" + df.format(mes) + "/" + ano; } }
class Empregado { private Data admissao; private Data nascimento; private String nome; public Empregado(Data admissao, Data nascimento, String nome) { this.admissao = admissao; this.nascimento = nascimento; this.nome = nome; } public String toString() { return "nome: " + nome + "\nnascimento: " + nascimento.toString() + "\nadmissao: " + admissao.toString(); } }
publicclass Form extends JFrame implements ActionListener { JTextField edtNasc, edtAdm, edtNome; public Form() { super("Composição"); Container c = getContentPane(); c.setLayout(new FlowLayout()); c.add(new JLabel("Nome:")); edtNome = new JTextField(20); c.add(edtNome); c.add(new JLabel("Nascimento:")); edtNasc = new JTextField(10); c.add(edtNasc); c.add(new JLabel("Admissão:")); edtAdm = new JTextField(10); c.add(edtAdm); JButton btnImprime = new JButton("Imprime"); c.add(btnImprime); btnImprime.addActionListener(this); this.setSize(400, 200); this.setVisible(true); }
publicstaticvoid main(String args[]) { new Form(); } publicvoid actionPerformed(ActionEvent e) { Data data1 = new Data(edtNasc.getText()); Data data2 = new Data(edtAdm.getText()); Empregado emp = new Empregado(data2, data1, edtNome.getText()); JOptionPane.showMessageDialog(null, emp.toString()); } }