Mau uso da Herança?

Olá pessoal,

gostaria de saber como vcs estruturariam a solução para a seguinte situação:

1 - Eu tenho uma interface TipoA com alguns métodos que são obrigatórios que todos os objetos que são do TipoA implementem;

2 - Eu tenho uma interface TipoB extends TipoA e TipoC extends TipoA, que estedem a interface TipoA com alguns métodos específicos que os objetos que implementam TipoB e TipoC precisam implementar.

3 - Por fim, tenho as classes TipoBDefault implements TipoB e TipoCDefault implements TipoC. Agora, na implementação dessas classes, a maioria dos métodos provenientes de TipoA possuem uma implementação comum, mas não todos. A pergunta é: onde colocar o código comum? Na minha opinião, o melhor (ou menos pior) seria colocar numa classe abstrata das quais TipoB e TipoC herdam, da seguinte forma:

class TipoBDefault extends AbstractTipoA implements TipoB {
   // implementacoes dos metodos declarados em TipoB
}

Mas, como bem observado no comentário do Fabio Kung no blog da Caelum ( http://blog.caelum.com.br/2006/08/26/ei-como-e-o-seu-dao-ele-e-tao-abstraido-quanto-o-meu/ ), este é um mau uso da herança, apenas para reutilização de funcionalidade.

Poderíamos quebrar essa classe abstrata, criando uma outra interface TipoComImplementacaoComum contendo apenas os métodos de TipoA cuja implementação é a mesma para ambas as classes TipoBDefault e TipoCDefault e então, injetamos essa dependência nessas classes, da seguinte forma:

class TipoBDefault implements TipoB {

   private TipoComImplementacaoComum implComum;

    public TipoBDefault(TipoComImplementacaoComum implComum) {
         this.implComum = implComum;
   }

  public X umMetodoQualquerDeclaradoEmTipoA() {
         return implComum.umMetodoQualquerDeclaradoEmTipoA(); 
  }

  public Y outroMetodoQualquerDeclaradoEmTipoA() {
         return implComum.outroMetodoQualquerDeclaradoEmTipoA(); 
  }

  public Z umMetodoQualquerDeclaradoEmTipoAComImplEspecifica() {
        // implementação específica
  }

  public W umMetodoQualquerDeclaradoEmTipoB() {
      // implementacao
  }
} 

Nesta última opção, teríamos a criação de uma interface a mais (mais um .java), com diversos métodos idênticos aos já declarados na interface TipoA (tudo bem, poderíamos fazer TipoA herdar desta outra interface). Sei que o exemplo ficou bem ruim usando esses nomes abstratos, mas, numa situação dessas, a herança a partir de uma classe abstrata não provoca tantos problemas, O que acham?

abraços

Não vejo problema na estrutura inicial, onde você cria uma AbstractTipoA. Afinal, suas implementações de TipoB e TipoC não são obrigadas a fazer um extends AbstractTipoA. Só fazem aquelas que realmente necessitam.

Agora, se você realmente se sente incomodado por usar isso, substitua pelo padrão Template Method e veja se é o caso.