Herança
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
Herança
Suponha agora que a classe ClasseB herda de ClasseA
Que métodos estão agora disponíveis para uma
referência da ClasseB (um objeto) ?
Herança
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
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
É UM
vs.
vs.
Composição
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:
::Project2
CA
m1(...)
m2(...)
CB
m3(...)
m4(...)
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.
::Project2
CA
m1(...)
m2(...)
m3(...)
m4(...)

CB
m3(...)
m4(...)
Desvantagem:

duplicação de métodos  dificulta a manutenção do software
Composição


2a soluçã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?
::Project2
CB
m3(...)
m4(...)
CA
m1(...)
m2(...)
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
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 {
private int dia;
private int mes;
private int 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));
}
df.format()
se
public String toString()
{ o campo tem apenas
um dígito
preenche com
// imprime a data no formato
dd/mm/aaaa
um zero à esquerda
DecimalFormat df = new DecimalFormat("00");
return df.format(dia) + "/" + df.format(mes) + "/" +
ano;
}
}
monta uma String no
formato dd/mm/aaaa
public 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;
monta uma String
}
contendo o nome, data de
nascimento e data de
admissão do Empregado
public String toString()
{
return "nome: " + nome + "\nnascimento: " + nascimento.toString() +
"\nadmissao: " + admissao.toString();
}
}
public class Teste
{
public static void main(String args[]) {
String aux = EasyIn.getString("Data do aniversario[dd/mm/aaaa]: ");
Data data1 = new Data(aux);
lê uma String contendo a
data de aniversário e usa
aux = EasyIn.getString("Data da admissao[dd/mm/aaaa]: ");
o método substring para
Data data2 = new Data(aux);
separar o dia, o mês e o
ano
aux = EasyIn.getString("nome: ");
Empregado emp = new Empregado(data2, data1, aux);
System.out.println(emp.toString());
}
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
private
private
private
{
int dia;
int mes;
int 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();
}
}
public class 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);
}
{
public static void main(String args[])
new Form();
}
{
public void 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());
}
}
Download

POO(Java).