GUJ Discussões   :   últimos tópicos   |   categorias   |   GUJ Respostas

Entendendo a hierarquia de classes (extends, implements)

Olá pessoal, resolvi escrever um tutorial para quem ainda tem duvidas sobre a hierarquia de classes em java, e gostaria de agradecer ao pessoal que tem me ajudado muito nos meus projetos, principalmente o Vini-Godoy!!!

Bom, começando… :!:

Uma hierarquia de classes, explicando melhor é um framework, ou seja um sistema mais complexo que uma simples classe, onde cada classe tem seus métodos, e variaveis, e principalmente sua função sobre o sistema.

No meu caso, eu estou criando um jogo de shooter vertical, em java e meu framework se encontra da seguinte maneira:

[code]public class nave extends Graficos implements KeyListener, LoopSteps
{
// corpo da classe
}

public class Graficos extends GameStatus
{
// corpo da classe
}

public class GameStatus extends Teclado
{
// corpo da classe
}

public class Teclado extends Variaveis
{
// corpo da classe
}

public class Variaveis extends Applet
{
// corpo da classe
}[/code]

Como podem notar, a minha hierarquia está gigante, eu poderia fazer o jogo todo em uma só classe, porém o unico problema de fazer em uma unica classe, colocando todos seus metodos nela, é de “morrer afogado no próprio codigo”, ou seja, se perder dentro do seu codigo, no meu caso estou criando uma Engine, ou seja, um projeto de jogo, onde eu poderei alterar futuramente o codigo, e alguns graficos, para criar a versão 2, e 3, e 4, etc, do jogo, podendo até mesmo criar outros jogos já que é um projeto bem organizado em classes.

Cada classe tem sua função:

nave -> Classe principal do jogo, que se encarrega de chamar os metodos correspondentes em outras classes.

Graficos -> Contém os métodos de pintura do jogo, nele estão o paint(), update(), e métodos de desenhar componentes do jogo.

GameStatus -> A thread principal chama o metodo gameStatus() de dentro dessa classe, para obter as ações atuais do jogo. Se a variavel game_status for igual a 0, carrega as imagens, se for igual a 1 exiba tela de entrada, etc.

Teclado -> Contém as ações do teclado, ou seja, se pressionar o botão faça isso, se pressionar o botao faça aquilo.

Variaveis -> Contém todas as variaveis, e seus metodos de inicialização para o sistema todo, além de herdar as funções da classe Applet, que contém os métodos essenciais para um applet java rodar, nesse caso, Variaveis é a super classe do projeto, e suas subclasses desde a classe nave obtém de forma indireta as propriedades da classe Applet, esse é o espírito da coisa.

Resumindo tudo, para fazer uma classe obter de forma direta acesso aos seus métodos e variaveis, usamos a palavra chave extends:

public class Classe1
{
int x = 200;
}
public class Classe2 extends Classe1
{
exiba (x);
}

Nesse caso, a Classe2 herda todos os métodos e variaveis da Classe1, podendo exibir a variavel x e recebendo o valor 200.

Caso na Classe2 existir também uma variavel x, por padrão ela será exibida, pois o java busca o x primeiro na classe atual, caso nao encontrar, irá checar as classes que ele herda os métodos, mas se caso isso acontecer, e você quer exibir o valor x da super classe Classe1, deverá usar a palavra chave super:

exiba (super.x);

ou para algum método é o mesmo caso, super.metodo1();

** A palavra chave implements…

A palavra chave implements serve para uma classe implementar uma interface, o que é uma interface? Uma interface é uma classe normal porém com seus métodos sem corpo, ela define um padrão de trabalho, para uma outra classe ver e implementar.

Por exemplo:

public interface Etapasweb { void criarSite(); void hospedarSite(); void divulgarSite(); }

[code]public class Webmaster implements Etapasweb
{
public void criarSite()
{
// corpo do metodo
}

[code]public void hospedarSite()
{
// corpo do metodo
}

public void divulgarSite()
{
// corpo do metodo
}

} // fim da classe[/code][/code]

Nesse caso temos uma classe Webmaster, que implementa a interface Etapasweb, uma interface como dito anteriormente é um conjunto de dados, assim como uma classe, porém essa define um padrão de comportamento a ser seguido rigidamente por uma outra classe. Se a classe Webmaster nao implementasse algum método da interface Etapasweb, geraria um erro na hora de compilar, isso se dá por causa da palavra chave implements.

Ao declarar implements Etapasweb voce disse que a classe Webmaster teria seus métodos implementados, então nesse caso a classe Etapasweb define como Webmaster tem que trabalhar, se voce é um webmaster e não hospeda o site por exemplo, nao estará seguindo o padrão de um webmaster, ou até se nao hospedar o site! :slight_smile: :)rsrss

A interface Runnable por exemplo, se voce implementa ela, deve obrigatoriamente implementar o corpo do método run(), porém isso ja entra em outra história (Threads).

Então é isso pessoal, espero que todos tenham entendido a importância de usar multiplas classes, e interfaces em um sistema complexo (framework).

Abraços :smiley: :smiley: :smiley: :smiley:

1 Curtida

Cara! Interface é só isso mesmo? Métodos sem corpo? É a primeira vez que vejo um exemplo :smiley: é a primeira vez que entendo :smiley: !

Sera que podia me informar quando acabasse o projecto ? Gostaria de saber como ficou.

Agradecido :lol:

Na hora de implementar, a interface é só isso mesmo. Uma “classe” cheia de métodos sem corpo, que pode ser “herdada” (na verdade, implementada) por qualquer um.

Mas a definição de interface é um pouco mais abrangente.

A interface representa um compromisso. Mais importante que os métodos, é o javadoc desses métodos! Ou seja, o contrato da interface.

O que eu quero dizer com isso? Eu entrego para você uma interface dizendo, “implemente esse, esse e esse métodos, dessa forma, e eu te forneço determinado serviço”.

Vamos fazer um exemplo bem simples. Vamos supor que você gostaria de uma classe que, dado um componente qualquer, imprimisse o nome dele, a altura e a largura. Essa classe você vai distribuir para terceiros, na sua framework. Então, você não sabe como o pessoal vai implementar esses componentes, se em swing, ou em swt.

Entretanto, o que você sabe? Que os componentes tem que ter um nome, uma altura e uma largura, certo? Para isso você modela uma interface:

public interface ComponenteImprimivel {
    /** Retorna o nome do componente. 
        O nome é um identificador único desse componente. */
    public String getNome();
    /** Altura do componente, não incluindo sua decoração. */
    public double getAltura();
    /* Largura do componente, não incluindo decoração */
    public double getLargura();
}

Pronto! Agora você pode fazer a sua classe que imprime:

public class ImpressoraDeComponentes {
     public void imprime(ComponenteImprimivel componente) {
            System.out.println("Nome: " + componente.getNome());
            System.out.println("Altura: " + componente.getAltura());
            System.out.println("Largura: " + componente.getLargura());
     }
}

Note que agora, sua classe ImpressoraDeComponente, pode funcionar com qualquer componente, seja Swing, AWT, SWT ou um criado por alguém que você ainda nem conhece. Basta que essa pessoa implemente a interface ComponenteImprimivel e, mais importante, retorne exatamente o que o seu contrato (javadoc) pede.

To começando a entender, é como se fosse um “mapa” dos métodos que tenho :?:

Só melhorando um pouco os termos.

Um framework não é sinônimo de uma aplicação complexa (embora muitos frameworks sejam, efetivamente, complexos).

Framework é um conjunto de bibliotecas ou classes que são usados para implementar uma estrutura padrão de uma aplicação. Normalmente, os frameworks se dedicam a facilitar uma tarefa específica.

A linguagem java seria muito pobre sem suas diversas frameworks. Por exemplo, o Swing é uma framework que te auxilia na construção de interfaces gráficas. A Collections Framework te fornece uma série de classes (List, Set, Hash, Queue) para lidar com coleções de objetos.

Existem também frameworks de terceiros. O Hibernate auxilia na tarefa de salvar objetos no banco de dados. O JMonkeyEngine auxilina na criação de jogos de computadores.

Alguns autores diferenciam Framework de Toolkit. Para eles, Framework é um conjunto de classes extensível, enquanto o Toolkit seria apenas um conjunto de classes interessantes, mas não feitas com a idéia de herança em mente. Nesse caso, o Swing seria uma framework, enquanto o HttpUnit, não.

Um mapa sim, mas não dos objetos que você tem, mas do que precisa ter para trabalhar.

Você diz para um terceiro.
“Eu tenho um framework que te ajuda nisso, nisso e naquilo”.

E o terceiro diz,
“ok, mas o que eu tenho que fazer para usar essa maravilha?”

Você responde:
“Simples, implemente esse conjunto de interfaces”.

Isso porque, a sua aplicação espera que quem implementou as interfaces que você produziu respeitem o contrato.

Veja o exemplo. Você poderia estar fazendo um programa gráfico, que pintasse objetos. Mas para isso, você precisaria de objetos coloridos, certo? Qual é a maneira mais simples de dizer “Ei, pessoal, eu preciso de objetos coloridos”?

A maneira mais fácil é essa:

public interface Colorivel {
     /** Retorna a cor da superfície do objeto. Nulo para transparente. */
     public Color getCor();
}

Pronto, agora, todos que quiserem usar sua classe de pintura, se deparão com um método do tipo:
pintarObjeto(Colorivel obj);

Quando você implementou o método pintar, você não se preocupou em como o objeto colorido foi implementado. Você apenas se preocupou com o fato de que ele era colorido, e tinha métodos que você precisava, com o comportamento que você esperava…

Se num jogo alguém quiser usar sua framework, poderia fazer:

public class Nave implements Colorivel

Agora, se alguém está fazendo uma aplicação de um livro infantil, e ainda sim quer usar sua framework faria:
public class CoelhoFofinho implements Colorivel

Na hora que você montou o método pintarObjeto, você não estava preocupado em saber quem exatamente seria o Colorivel. Para você tudo estaria bem, desde que fosse um Colorivel qualquer. É isso que a interface mostra. Ela diz que “Para meus métodos de pintura, um objeto colorido é alguém que tem o método getCor(), que retorna uma cor ou nulo, se o objeto for transparente”.

Cara, você está explicando muito bem, mas ainda não entendi bem a real utilidade de se usar uma interface. Se ela apenas define métodos que, quem herdá-la (a classe), terá de implementá-los, não iria ser a mesma coisa de eu criar a minha classe e implementá-lo do mesmo jeito?

O que eu não consigo entender é o porquê de utilizá-la, não encontro uma razão óbvia. Toda a implentação do método vai estar na sua classe principal. De que me vale adquirir um “contrato”, como muitos dizem, que no final das contas o “grosso” do método quem irá fazer sou eu?

É diferente, por exemplo, de herança, que você apenas acrescenta às funcionalidades da super classe, e ela já lhe fornece muitos serviços prontos. A interface não me fornece nenhum serviço. Apenas me restringe ao que eu tenho de implementar.

Realmente, isso ainda está difícil de abstrair…

Oi Vinicius, então no caso o framework que eu quis dizer é meu conjunto de métodos e interfaces que já segue um padrão para criar o jogo da nave, ou seja, um projeto mais complexo que um applet normal, porém que pode ser reutilizavel.

[quote]Ehb


Sera que podia me informar quando acabasse o projecto ? Gostaria de saber como ficou.

Agradecido [/quote]

Ehb, eu acho que vai demorar um pouquinho, pois ando muito ocupado com outras coisas e não tive muito tempo pra mandar bala no programa, mas assim que o jogo ficar pronto eu posto aqui no GUJ o link para jogar online.

[quote]bzy

Cara! Interface é só isso mesmo? Métodos sem corpo? É a primeira vez que vejo um exemplo é a primeira vez que entendo ! [/quote]

Bzy, interface é apenas isso mesmo, porém o diferencial de uma interface não é seus métodos sem corpo, e sim o padrão que ela manda uma classe seguir, é como se ela fosse o patrão, e te dá 3 tarefas:

[code]public interface Patrao
{
void fazerRelatorios();
void visitarClientes();
void reuniao();
}

public class Funcionario implements Patrao
{
public void fazerRelatorios()
{
// corpo do metodo implementado
}
public void visitarClientes()
{
// corpo do metodo implementado
}
public void reuniao()
{
// corpo do metodo implementado
}
}[/code]

Se a classe Funcionario implementar a Interface Patrao, ela deverá implementar por obrigação todos seus métodos, é o mesmo que se voce entrar numa empresa, terá que fazer todos as etapas que seu patrão te passar, nesse caso o Patrao é a interface, se caso algum método da interface nao for implementado gera erro de compilação.


Outra coisa que notei que bastante gente tem duvida, é sobre a palavra chave super com multiplas classes. Exemplo:

[code]public class Super
{
int x = 200;
exiba (x); // ele exibirá 200, que é o x da classe atual, ela nao pode acessar as subclasses, pois nao herda (extends) dados, e sim herdam (extends) dados dela…

}
public class Sub1 extends Super
{
int x = 150;
exiba (super.x); // exibirá 200 também, pois esse super está relaciona a super classe de Sub1, que é Super…

}
public class Sub2 extends Sub1
{
int x = 100;
exiba (super.x); // exibirá 150, esse super estã relacionado a super classe de Sub2, que no caso é Sub1, Sub2 é a classe C portanto indiretamente acessa o conteúdo da super classe, ja que a classe B Sub1 herda os dados da super classe Super, e por sua vez é obtido pela subclasse Sub2.
}[/code]

Certo pessoal :?:

Abraços :!: :!: :!:

[quote]Reilander

Cara, você está explicando muito bem, mas ainda não entendi bem a real utilidade de se usar uma interface. Se ela apenas define métodos que, quem herdá-la (a classe), terá de implementá-los, não iria ser a mesma coisa de eu criar a minha classe e implementá-lo do mesmo jeito?

O que eu não consigo entender é o porquê de utilizá-la, não encontro uma razão óbvia. Toda a implentação do método vai estar na sua classe principal. De que me vale adquirir um “contrato”, como muitos dizem, que no final das contas o “grosso” do método quem irá fazer sou eu?

É diferente, por exemplo, de herança, que você apenas acrescenta às funcionalidades da super classe, e ela já lhe fornece muitos serviços prontos. A interface não me fornece nenhum serviço. Apenas me restringe ao que eu tenho de implementar.

Realmente, isso ainda está difícil de abstrair… [/quote]

Reilander, eu também penso assim, por isso que meu projeto tem mais classes do que interface, e mais extends do que implements.

Porém é interessante saber que as interfaces possuem um papel ótimo também para definir um padrão de trabalho totalmente organizado. :!:

Mas explicando aqui uma interface que tenho no meu jogo, que é a interface LoopSteps, e a classe MainLoop…

MainLoop cria uma instancia da interface dessa maneira:

private LoopSteps game;

E invoca seus métodos:

game.processLogics(); // processa todas as funções do jogo
game.paintScreen(); // pinta na tela do jogo
game.renderGraphics(); // prepara o buffer para ser desenhado

Só que dentro da interface esses métodos se encontram da seguinte maneira:

void processLogics();
void paintScreen();
void renderGraphics();

Lembrando que a classe MainLoop apenas cria a instancia game da interface LoopSteps, e na hora certa chama seus métodos, porém o que será executado??? Nada!!! E se eu implementar a interface LoopSteps? O que será executado??? Os métodos implementados !!!

Observe que ai, MainLoop é uma classe que foi feita pra trabalhar com qualquer outra classe, sem precisar conhecer o nome de tal classe, apenas utilizando o padrão da interface LoopSteps, é possivel trabalhar com MainLoop.

Em outros detalhes, MainLoop é o presidente, LoopSteps é o diretor, sua classe que implementa LoopSteps é o funcionario.

MainLoop vai requisitar as tarefas a quem? Ao funcionario direto ou ao diretor? Ao diretor é claro.

E o diretor irá passar as tarefas requisitadas, a quem se contratar para o emprego, por exemplo:

[code]public class Funcionario implements Diretor
{
// voce acabou de conseguir um emprego, agora faça suas tarefas (implemente os métodos).

public void fazerRelatorios()
{
// corpo do metodo implementado
}
}

public class MainLoop
{
// Classe “presidente”…
private LoopSteps game;

game.fazerRelatorios();
}

public interface LoopSteps
{
void fazerRelatorios();

// eu nao tenho que fazer nada, quem faz é os funcionarios que me implementam (trabalham comigo), na chamada desse método, um funcionario que estiver me implementando que fará essa ação solicitada pelo Presidente
}[/code]

Entendeu? Isso tudo define já um padrão a ser seguido, só que este caso é mais complexo, porém muito mais util!

Entendeu? Qualquer duvida postem ai!!!

Abraços :smiley: :smiley: :smiley:

Reilander,

Entenda o seguinte.

  1. Você pode usar interfaces para definir contratos para classes que a implementação não será você quem vai fazer. Na verdade, você não tem nem idéia do que a pessoa que irá implementa-las vai fazer. Foi o caso da Nave e do CoelhoFofinho, no exemplo que passei. Quem implementou essas classes foram os clientes. Por isso, o cliente (no caso, outros programadores), devem ser restringidos pela interface, sem que sejam restringidos na hierarquia de classes que eles quiserem montar.

Veja por exemplo a interface ActionListener, do Swing. As pessoas que implementaram o Swing não sabiam que tipo de ação seria implementada, ou que classe implementaria a ação. Apenas sabiam que os usuários do swing esperavam que algum método fosse chamado quando actionPerformed fosse evocado.

  1. Você pode usar interfaces para prover serviços para hierarquia de classes diferentes. Por exemplo, suponha que você tem a classe Carro, e a classe Cachorro. Ambos são coloridos, mas pertencem a hierarquias completamente diferentes. Portanto, você poderia usar o método de pintura que eu sugeri no exemplo acima, desde que ambas implementassem Colorivel.

  2. O acoplamento do código é muito menor quando se usa interfaces do que quando se usa classes. Você passa a depender do serviço que a interface presta, não da implementação desse serviço. Veja por exemplo o caso do List. A interface List define uma lista de objetos, certo? Então eu posso dizer que o método abaixo funciona tanto para um ArrayList, quanto para um LinkedList, simplesmente recebendo um List como parâmetro:

public void imprimeLista(List umaLista) {
     for (int i = 0; i &lt umaLista.size(); i++) {
           System.out.println(umaLista.get(i).toString());
     }
}

Note que, quando implementei o método, não estou preocupado em qual implementação específica de lista estou usando, desde que, a classe em questão siga à risca o contrato da interface List, que representa uma lista. Eu poderia até mesmo implementar uma classe Baralho, que se comportasse com uma lista (e que não tivesse absolutamente nada a ver com as classes do Java) mas, se essa classe implementasse a interface List, esse método continuaria funcionando.

Uma dica.

Leiam essas entrevistas (em inglês) com o Erich Gamma, criador do JUnit, Eclipse e um dos autores do livro Design Patterns.

http://www.artima.com/lejava/articles/designprinciples.html
http://www.artima.com/lejava/articles/reuse.html

Nessas entrevistas, ele explica porque é importante projetar sistemas usando interfaces, e não classes concretas. E também fala um pouco sobre frameworks, toolkits e aplicações reutilizáveis.

São um pouco longas, mas valem muito à pena! :slight_smile:

Hum… se eu eu entendi bem, interfaces são úteis mais para padronização que para implementação. O que digo é, ao invés de cada classe, como no seu exemplo, usar um método peculiar de impressão, você tem certeza de que, se ela implementar a interface LoopSteps, ela terá um método paintScreen(). Bom, se eu criasse uma classe abstrata com todos esses três métodos abstratos o efeito seria o mesmo se eu a herdasse, não é? Mas digamos que, implementando uma interface, o código fica mais “elegante” e padornizado.

Agora, uma outra coisa que eu não entendi. Em um exemplo, você instanciou uma classe abstrata. Isso realmente é possível, ou você o fez apenas pra efeitos didáticos, facilitando sua explicação? Porque, se me lembro bem, como os métodos não são implementados, as interfaces não podem ser instanciadas. Mesmo que haja objetos criados e que os implementam, quando eu invocasse um de seus métodos, qual o método que ele invocaria, realmente? Bem, fica aí a dúvida.

Outra coisa: cara, valeu mesmo pelo teu esforço aí em explicar essas coisas. Este fórum do GUJ é fora de série. Gosto muito dele por causa de pessoas como tu - ViniGodoy. Estás ajudando muito, brother!

Isso, padronização é um dos casos.

O problema das classes abstratas é que cada classe pode extender somente uma superclasse. Agora, voltemos ao exemplo do Colorivel.

Tanto Carro (que é filho de Automóvel, que é filho de Object) e
Cachorro (que é filho de Animal, que é filho de Object) gostariam de usar dos serviços do método pintarObjeto, que precisa de um Colorivel.

Vamos agora supor que Colorivel não é uma interface e sim uma classe e ver que problemas teremos:

  1. Colorivel teria que ser pai de Animal, não de Cachorro. Afinal, Cachorro não pode extender ao mesmo tempo Animal e Colorivel;

  2. Da mesma forma, Colorivel teria que ser pai de Automóvel. Veja que não só temos o problema 1 novamente, como agora criamos um relacionamento entre Animal e Automóvel (já que ambos são filhos da mesma superclasse);

  3. Agora vamos supor que tivessemos diversos serviços como imprimirObjeto. Além de Colorivel, tivessemos super classes para ObjetoComTextura, Objeto3D, etc… Como ficaria a hierarquia de classes? Esse problema é especialmente ruim se apenas parte das classes de sua hierarquia é em 3D, outra parte tem textura e outra parte é colorida. Tente imaginar, usando superclasses, um diagrama dos filhos de animal, onde Cachorro e Gatos são coloridos, Gatos e Patos tem textura e Cachorros e Patos são em 3D.
    Lembre-se, você quer separar a classe de pintura em:

public class Pintora {
  public void desenharEm3D(Objeto3D objeto) {...}
  public void pintarObjeto(Colorivel objeto) {...}
  public void renderizarTextura(ObjetoComTextura objeto) {...}
}

Pense um pouco nesses problemas… espero que daí você entenda a necessidade das interfaces.

A propósito, você falou que uma classe abstrata foi instanciada num dos exemplos. Em qual exemplo foi e que classe foi essa? Nem classes abstratas e nem interfaces podem ser instanciadas.

Mas você pode usar uma interface ou classe abstrata para referenciar uma instância da filha. Por exemplo:

Colorivel objeto = new Cachorro();

O método objeto.getCor() vai mostrar a cor do cachorro.

Tanta coisa que vou ter que ler novamente com calma :smiley: .
Mas pelo que entendo, tem coisas que são obrigatórias-obrigatória e coisas obrigatórias-úteis.
Oque seria as coisas obrigatórias-obrigatória > Seria a programação normal que não fucniona de outra maneira…
E as
obrigatórias-úteis > seriam como os comentários, as interfaces e até os privates, public e etc. São obrigatórios porque ajudam, mas pode fazer um programa inteiro sem nenhum comentário (e coitado de quem vier depois) como pode se fazer o contrário. Acho que a Interface é um desses casos. Mas eu acho que só irei entender mesmo quando usar em algum projeto meus, espero poder compartilhar e contar com vocês :smiley:

Valeu pessoal.

Normalmente, a compreensão da interface vem quando você quer,

  1. separar o seu projeto em camadas distintas, não dependentes uma da outra ou
  2. Quando você está projetando um programa para ser usado por outros programadores.

Mas não se aflija, é normal no começo. A medida que você for estudando OO e os Padrões de Projeto, você vai vendo mais e mais usos interessantes de interfaces, e você acaba fixando o conceito.

Falando no assunto, outro dia estava fazendo um projeto CRUD bastante separado em camadas, e Interfaces foram muito úteis.

No caso minha hierarquia era a seguinte:
Um daoGenerico para salvar, incluir, excluir e selecionar meus objetos persistentes.
A camada BO que representava as regras de negócio.
O Facade, que dava acesso aos BOs de forma simplificada para o que estivesse acima, e ainda abria e fechava as transações.

Nesse caso, percebi que para cada classe do BO eu teria pelo menos uns 4 metodos no Facade. Com o passar do tempo se tornaria uma classe gigante e difícil de mexer. Como os metodos chamavam BOs diferentes com métodos diferentes cada um, era quase impossível simplificar.

Aí então resolvi criar uma interface que os BOs implementaria, com os métodos CRUD. Então precisou apenas que no Facade eu tivesse um método para incluir, um para excluir, etc, que poderia ser usados para invocar todos os BOs que tivesse, sem que eu precisasse escrever mais código. Isso junto com um pouco de reflection facilitou demais a minha vida nesse ponto.

Parabéns pela iniciativa…Um material como esse teria me ajudado muito há 4 anos atrás…

:Dque exemplo rico de explicação…
AS

//