Herança: Uma sugestão?

Olá pessoal :smiley:

Estou montando um projetinho, que possui as seguintes entidades: Cliente, Vendedor e Fornecedor.
Eu queria usar herança para estas entidades, fazendo com que estas extendem os atributos em comum, da classe pai, que seria Usuario.

Porém, o Cliente é o único que não se loga no sistema, logo, ele não precisa de login nem senha, mas os demais sim.

Alguém teria uma sugestão para este probleminha? :smiley:

Faça uma superclasse para as tres, depois um subclasse dessa que seja superclasse das outras duas que possuem mais campos em comum…

Seria algo do tipo:

[code]public abstract class Pessoa {
private Integer id;
private String nome;
}

public abstract class Usuario extends Pessoa(){
private String login;
private String senha;
}

public class Vendedor extends Usuario(){
}

public class Fornecedor extends Usuario(){
}

public class Cliente extends Pessoa(){
}[/code]

Algo desse tipo?
É pq eu vou jogar os annotations do Hibernate pra mapear as entidades, teria algum exemplo de uma implementação dessa usando Hibernate?

Abraços.

Hibernate e herança?
http://www.hibernate.org/hib_docs/annotations/reference/en/html/entity.html#d0e829

Valeu kra! vou dar uma olhada!
A respeito da arquitetura que postei acima, é correto utilizá-la?

Fala cara,

Eu sou meio contra herança (heresia!!!).

Existem dois motivos para se usar herança, o mau e o bom. O mau motivo é usar herança pra fazer reuso de código: “bem, se estas duas classes aqui têm um método calculatePrice()” que é igual, então vou criar uma classe base AbstractPriceable e botar o método nela!!".

Este é um mau motivo porque você acopla duas classes que não deveriam ter nada a ver uma com a outra. Só se deve fazer herança quando houver uma relação “É-UM”. Um exemplo de livro-texto: você pode ter a classe base Shape, e a classe filha Circle extends Shape. Isso porquê Circle “É-UM” Shape E você tem situações legítimas onde você quer trabalhar com objetos Shape de maneira genérica sem se importar se ele é um Circle, Square ou Rectangle – apesar de que eu prefereria usar interfaces neste caso.

No seu exemplo, a princípio parece fazer sentido que Cliente “É-UM” Usuario.

Mas será que Usuario é realmente a abstração em comum de Cliente, Vendedor e Fornecedor? Você mesmo diz que Cliente não se loga no sistema. Acho que você está escolhendo a abstração errada para a classe base. Há situações onde você precisa usar a classe Usuario de maneira genérica, não importando se a classe concreta é Cliente, Vendedor ou Fornecedor? Mesmo que a resposta for SIM, você pode considerar usar interfaces ao invés de herança.

Quanto a esse exemplo aí, se resolver fazer assim tome cuidado como vai mapear no Hibernate, porque você pode acabar com Clientes, Vendedores e Fornecedores todos misturados na tabela PESSOA. Provavelmente ficaria mais limpo se você tivesse as tableas CLIENTE, VENDEDOR E FORNECEDOR OU talvez uma tabela CLIENTE e outra USUARIO onde USUARIO pode ser Vendedor ou Fornecedor. Me parece fazer mais sentido. \Outra coisa, usar herança apenas para reusar os campos id e nome me parece desnecessário.

[quote=felipempantoja]Seria algo do tipo:

[code]public abstract class Pessoa {
private Integer id;
private String nome;
}

public abstract class Usuario extends Pessoa(){
private String login;
private String senha;
}

public class Vendedor extends Usuario(){
}

public class Fornecedor extends Usuario(){
}

public class Cliente extends Pessoa(){
}[/code]

Algo desse tipo?
É pq eu vou jogar os annotations do Hibernate pra mapear as entidades, teria algum exemplo de uma implementação dessa usando Hibernate?

Abraços.[/quote]

Felipe, na minha opinião o que você deve levar em consideração quando for usar herança é se seu objeto realmente “É UM” tipo do outro. Por exemplo: Pergunte a você mesmo se seu Vendedor é um Usuário ou se em determinados momentos ele se comporta ou assume papel de um. Neste caso vejo como melhor alternativa o uso de Composição para compartilhar os atributos em comum e como seu objeto Vendedor e Fornecedor assumem papel de um Usuário, você deveria criar um interface Usuário e fazer com que seu Vendedor e seu Fornecedor implementem ela, aproveitando assim o poder do polimorfismo.

E costumo pensar em herança não definindo uma superclasse para classes, mas sim uma subclasse para as classes.

A diferença é que você acaba pensando em especialização e não em generalização. Dá mais certo.

Por esse lado, olhando superficialmente, Vendedor, Fornecedor e Cliente fazem parte de uma mesma parte do sistema, Vendas, mas Usuário não tem nada a ver com isso. Também não importa que Vendedor, Fornecedor, Cliente e até mesmo Usuário herdem de Pessoa. Por acaso eles não não podem ser Empresas? Não me venha com “Empresa é Pessoa Jurídica”. A venda pode ser para um grupo de pessoas, sem PJ. Vai obrigar elas a usarem CPF ou CNPJ p/ poder executar a venda? Perdeu um cliente.

Se dois deles são usuários, por que não nomeá-los UsuárioVendedor, UsuárioFornecedor? Aí sim seriam especializações de Usuário.

Se você puder, evite utilizar herança, prefira composição.

Boa leitura: http://blog.caelum.com.br/2006/10/14/como-nao-aprender-orientacao-a-objetos-heranca/

Fala pessoal, obrigado pela ajuda!

Cara, sinceramente, o único momento que eu usaria a classe Usuario de maneira genérica, seria na autenticação, já que eu não sei quem está logando, mas quanto ao cliente, de fato só pensei em herança justamente pra reuso.

Não são somente estes campos, coloquei só pra exemplificar.

O uso de interfaces poderia ser uma boa solução, assim como o Domingos falou. O Hibernate suporta essa hierarquia?

[quote=Bruno Laturner]E costumo pensar em herança não definindo uma superclasse para classes, mas sim uma subclasse para as classes.

A diferença é que você acaba pensando em especialização e não em generalização. Dá mais certo. [/quote]
Bruno, teria como me dar um exemplo bem simples? Não acompanhei a linha de raciocínio :smiley:

[quote=rcarneiro]Se você puder, evite utilizar herança, prefira composição.

Boa leitura: http://blog.caelum.com.br/2006/10/14/como-nao-aprender-orientacao-a-objetos-heranca/[/quote]
Opa, valeu cara, estou lendo aqui! Obrigado pela referência.

[quote=felipempantoja]Estou montando um projetinho, que possui as seguintes entidades: Cliente, Vendedor e Fornecedor.
Eu queria usar herança para estas entidades, fazendo com que estas extendem os atributos em comum, da classe pai, que seria Usuario.

Porém, o Cliente é o único que não se loga no sistema, logo, ele não precisa de login nem senha, mas os demais sim.

Alguém teria uma sugestão para este probleminha? :smiley: [/quote]
Felipe, utilizar herança para reaproveitar atributos é uma péssima ideia. Pra avaliar o uso de uma herança correta você precisa pensar em espaço-estado, invariantes, pré/pós condições, e uma série de outras coisinhas pra não correr o risco de fazer uma bela cagada no design da sua aplicação.

[]s

Opa Emerson, obrigado pela resposta :smiley:

Na verdade não foi uma herança única e exclusivamente para reaproveitar atributos, eu acredito que realmente faça sentido o uso da herança neste modelo de classes, já que um Usuário (usuário do sistema) é uma Pessoa, assim como Cliente é uma Pessoa, e indo mais além, um Vendedor e um Fornecedor pertencem a classe Usuario, já que ambos acessam o sistema.

Eu li um pouco nos últimos dias sobre o uso da composição ao invés da herança, a questão é, se é possível usar composição com Hibernate :smiley:

Procurei alguma coisa na internet porém, sem sucesso.

Opa Emerson, obrigado pela resposta :smiley:

Na verdade não foi uma herança única e exclusivamente para reaproveitar atributos, eu acredito que realmente faça sentido o uso da herança neste modelo de classes, já que um Usuário (usuário do sistema) é uma Pessoa, assim como Cliente é uma Pessoa, e indo mais além, um Vendedor e um Fornecedor pertencem a classe Usuario, já que ambos acessam o sistema.[/quote]
A forma de você definir esse E-UM não pode ser simplesmente baseado na intuição. Dá uma lida em [Page-Jones, 1999] que explica bem sobre o assunto. Na internet tem material mais básico sobre o assunto tb. :wink:

[quote=felipempantoja]Eu li um pouco nos últimos dias sobre o uso da composição ao invés da herança, a questão é, se é possível usar composição com Hibernate :smiley:

Procurei alguma coisa na internet porém, sem sucesso.[/quote]
A annotation @Embedded talvez te ajude.

Emerson, valeu pelas dicas :smiley:
Vou dar uma pesquisada sobre o assunto e entender essa annotation :smiley:

Abração!