[Modelagem] Composicao de classe em classe abstrata

Ola pessoal,

Estou recorrendo a voces do forum pois estou com uma duvida na modelagem de um sistema, em seguida vou explicar como funciona.

Tenho uma Classe Mae, abstract, chamada Pessoas, nela tenho um atributo registrado, onde é “registrado” o status da pessoa, “Normal” ou “Admin”;
Pessoas tem de heranca a classe Projetistas,ChefeEquipe e ChefeProjeto.
Se a pessoa é registrada como Normal, ok, ela possui os metodos da classe Mae.
Se a pessoa é registrada como Admin, alem dela ser um objeto do tipo Projetistas, ChefeEquipe, ChefeProjeto, ela tem metodos especificos do Admin.

Coloquei a imagem sem a relacao da classe Admin com as demais.

Aceito sugestoes pra resolver o problema, bem como discutir mudanca na modelagem.

PS: Isso sera mapeado e salvo no banco de dados.

Obrigado


Bom dia amigo.

Eu penso que se a classe Admin possuirá todos os atributos da classe Pessoas, ela tambem deve extender a mesma.

[]'s

Agora que eu vi direito, essas três classes que extendem Pessoas, podem ser administradoras, certo! Você pode instanciar a classe Admin quando alguma dessas três classes for administradora, Projetistas, ChefeEquipe e/ou ChefeProjeto.

[]'s

Bom dia getAdicted,

Bom, no comeco pensei que seria dessa forma, mas note que, se uma pessoa é Chefe de Equipe, ela tem metodos especificos da classe, e se ela poussir ainda o status de Admin, ela possuira os metodos do Admin e mais os metodos do chefe de equipe.

Espero que tenha ficado claro agora.

Amplexo

Sim, exato, mas qual seria a relacao entre as classes Pessoas e Admin?

Penso em usar o metodo de fabrica, para ficar mais claro.

Amplexo

De acordo com o que você modelou, o que vêm a cabeça eh isso:

public class Administrador {

}

[code]public abstract class Pessoa {

}
[/code]

public class Projetista extends Pessoa{

}
public class ChefeEquipe extends Pessoa{

}

[code]public class ChefeProjeto extends Pessoa {
private Administrador admin;

public Administrador getAdmin() {
	return admin;
}

public void setAdmin(Administrador admin) {
	this.admin = admin;
}

}
[/code]
Repare que a entidade ChefeProjeto eh administradora, portanto, você instanciará a classe Admin. Mas tem uma abordagem melhor, eh soh pensar mais um pouco.

[]'s

Qual abordagem é melhor?

Pensei aqui e nao tive idéia melhor.

Obrigado

[quote=andrielc]Qual abordagem é melhor?

Pensei aqui e nao tive idéia melhor.

Obrigado
[/quote]

Usar Herança para representar papeis de pessoas não é uma boa. É simplesmente a ferramenta errada.
Poderia fazer com Interfaces, Assim a Pessoa pode ser Chefe e Administrador ao mesmo tempo. Contudo, sistemas de roles (papeis) são feitos de outra forma.
A classe é Role (Papel) e instancias dessa classe representam papeis diferentes (através de num codigo unico ou um nome. normalmente um nome ). O Role pode ser uma enum, em sistemas mais simples
A classe Pessoa tem uma lista de Role. Assim é possível perguntar para o objeto pessoa se ele é de um role especifico.
Os métodos não ficam na pessoa. ficam no sistema, e o sistema pergunta à pessoa se ela tem um role especifico ( tipo quando o porteiro pergunta se vc tem RG).
Sistema seguros não perguntam diretamente à pessoa (porque ela pode mentir), pergunta a um terceiro que é confiável.

O mecanismo de Roles não é só para segurança Pode ser usado no dia-a-dia da aplicação.

Se realmente por necessário ter interfaces, o ideal é criar elas a partir da pessoa assim

Administrador admin = pessoa.as(Role.ADMIN);

Se a pesoa não for admin, o método ‘as’ retorna nulo, ou lança exceção.

sergiotaborda,

Como voce citou sobre interface, transformei minha classe pessoa como interface,

projetistas, chefe de equipe e chefe de projeto implementa Pessoa.

Duas duvidas, a interface Pessoa tem os atributos antes designado a ela, ou em cada classe que implementar a pessoa devo colacar os mesmos atributos com gets/sets?

[code]@MappedSuperclass
public interface IPessoa extends Serializable {

//atributos
@Id
@Column (name = "LOGIN")
String login = null;

@Column(name = "NOM")
String nom = null;

@Column(name = "PASSWORD")
String password = null;

@Column(name = "NOM_GROUP")
String nomGroup = null;


//get and sets


//Methodes

[/code]

@Entity public class PessoaProjetista implements IPessoa{ //implementacao de funcoes da interface ... }

@Entity public class PessoaChefeEquipe implements IPessoa{ //implementacao de funcoes da interface ... }

@Entity public class PessoaChefeProjeto implements IPessoa{ //implementacao de funcoes da interface ... }

[code]public class Admin {
//implementacao de funcoes da classe admin

}[/code]

Como seria a implementacao do chefe administrador, como voce tinha sugerido ?

Obrigado

[quote=andrielc]sergiotaborda,

Como voce citou sobre interface, transformei minha classe pessoa como interface,

projetistas, chefe de equipe e chefe de projeto implementa Pessoa.

Duas duvidas, a interface Pessoa tem os atributos antes designado a ela, ou em cada classe que implementar a pessoa devo colacar os mesmos atributos com gets/sets?

[code]@MappedSuperclass
public interface IPessoa extends Serializable {

//atributos
@Id
@Column (name = "LOGIN")
String login = null;

@Column(name = "NOM")
String nom = null;

@Column(name = "PASSWORD")
String password = null;

@Column(name = "NOM_GROUP")
String nomGroup = null;


//get and sets


//Methodes

[/code]

@Entity public class PessoaProjetista implements IPessoa{ //implementacao de funcoes da interface ... }

@Entity public class PessoaChefeEquipe implements IPessoa{ //implementacao de funcoes da interface ... }

@Entity public class PessoaChefeProjeto implements IPessoa{ //implementacao de funcoes da interface ... }

[code]public class Admin {
//implementacao de funcoes da classe admin

}[/code]

Como seria a implementacao do chefe administrador, como voce tinha sugerido ?

Obrigado[/quote]

Você entendeu ao contrário. Pessoa é a classe. Ela tem as propriedades.
Os outros que são interfaces e não herdam de pessoa.
A pessoa tem um conjunto de roles

public interface ChefeEquipe extends Role {
//implementacao de funcoes da interface
...
}

@Entity
public class Pessoa {

 Collection<BusinessRole> roles;

 public <T as Role> T asRole(Class<T> type){
         if (ChefeEquipe .class.isAssignableFrom(type)){
                 if (!this.hasRole(ChefeEquipe .class)){
                     return null;
                 }   
                 return new ChefeEquipe (){

                            // nested class com os gets do administrato que são lidos dos private de pessoa.
                    }
           } else if ( ... ){

         } 

 } 
}

Você está tentando forçar uma herança que não existe. Talvez deva analizar porque vc está querendo isso. Administrador é um papel de segurança do sistema, chefe de equipe é um papel de negocio.
O primeiro tem que ver com o login do usuário, o se segundo tem que ver com alguma estrutrua no seu sistema. acho que cabe vc explicar melhor o contexto do projeto e porquê vc quer fazer esta salganhada toda.

Bem,

O projeto é descrito na imagem anexada.

O que quero fazer é um sistema de registro de horas de trabalho.
Cada pessoa é ligada a um projeto ou tarefa, conforme o administrador escolher.
As pessoas sao armazenadas no banco de dados, bem como os projetos e tarefas.

Facilitando assim para gerar relatorio para o administrador e para o chefe de projeto.

Qualquer duvida a respeito da modelagem so falar.

Criticas sao muito bem vinda, estou comecando agora.

Obrigado


[quote=andrielc]Bem,

O projeto é descrito na imagem anexada.
[/quote]

Pode ser que sim, mas aquilo não é descrição o bastante.( aliás, aquilo é o quê ? UML ? Modelo ER? Ou umas mistura ? se for UML as setas estão ao contrário)
Aquilo é o modelo comceptual ou fisico? Para mim seria no máximo conceptual.

Vc já tem a entidade pessoa. Vc não precisa de herança. Crie uma class TipoDePessoa e classifique a pessoa com o tipo. Pronto.
O ser administrador ou não é uma questão que precisa resolver com o conceito de Usuário e não como o de pessoa.
O seu objeto pessoa não deve características de usuário (username, password, etc…). É porque vc está pondo muita responsabilidade numa classe só que vc está com problemas.

Não use herança quando vc pode usar composição. E esqueça a questão das interfaces e das classes. Faça uma só entidade Pessoa com tipo e pronto.
Vai até facilitar na hora dos relatórios.

Faça bem simples.

[quote=sergiotaborda]
Pode ser que sim, mas aquilo não é descrição o bastante.( aliás, aquilo é o quê ? UML ? Modelo ER? Ou umas mistura ? se for UML as setas estão ao contrário)
Aquilo é o modelo comceptual ou fisico? Para mim seria no máximo conceptual.

Vc já tem a entidade pessoa. Vc não precisa de herança. Crie uma class TipoDePessoa e classifique a pessoa com o tipo. Pronto.
O ser administrador ou não é uma questão que precisa resolver com o conceito de Usuário e não como o de pessoa.
O seu objeto pessoa não deve características de usuário (username, password, etc…). É porque vc está pondo muita responsabilidade numa classe só que vc está com problemas.

Não use herança quando vc pode usar composição. E esqueça a questão das interfaces e das classes. Faça uma só entidade Pessoa com tipo e pronto.
Vai até facilitar na hora dos relatórios.

Faça bem simples.[/quote]

O que é aquilo? É um modelo conceitual de implementação, pra saber de onde partir, utilizei conceito de UML pra fazer ligações entre as classes.

Certo, entendi o seu ponto, porém, cada tipoPessoa tem métodos diferentes e se eu fizer a divisão de Usuário / Pessoa, no Banco de Dados não haverá uma ligação clara de qual usuário tem que nome, trabalha em tal projeto, a referência se perde.

Se eu fizer como você disse, a pessoa Projetista será apenas uma Pessoa tipo Projetista, ela nunca poderá também ser um Administrador. Nota que o sistema pode haver mais que um Administrador independente do tipoPessoa.

Espero que tenha esclarecido mais ainda.

Fico no aguardo.

Obrigado pela ajuda e explicações.

[quote=andrielc][quote=sergiotaborda]
Pode ser que sim, mas aquilo não é descrição o bastante.( aliás, aquilo é o quê ? UML ? Modelo ER? Ou umas mistura ? se for UML as setas estão ao contrário)
Aquilo é o modelo comceptual ou fisico? Para mim seria no máximo conceptual.

Vc já tem a entidade pessoa. Vc não precisa de herança. Crie uma class TipoDePessoa e classifique a pessoa com o tipo. Pronto.
O ser administrador ou não é uma questão que precisa resolver com o conceito de Usuário e não como o de pessoa.
O seu objeto pessoa não deve características de usuário (username, password, etc…). É porque vc está pondo muita responsabilidade numa classe só que vc está com problemas.

Não use herança quando vc pode usar composição. E esqueça a questão das interfaces e das classes. Faça uma só entidade Pessoa com tipo e pronto.
Vai até facilitar na hora dos relatórios.

Faça bem simples.[/quote]

O que é aquilo? É um modelo conceitual de implementação, pra saber de onde partir, utilizei conceito de UML pra fazer ligações entre as classes.

Certo, entendi o seu ponto, porém, cada tipoPessoa tem métodos diferentes e se eu fizer a divisão de Usuário / Pessoa, no Banco de Dados não haverá uma ligação clara de qual usuário tem que nome, trabalha em tal projeto, a referência se perde.
[/quote]

Como assim ? Você faz o Usuário ter uma Pessoa ( ou a Pessoa ter um usuário). Nada se perde. Mas vc isola os conceitos. Vc poderá ter usuários que não são pessoas e vice-versa.
Isso é mais poderoso que o que tem agora, em que todas as pessoas são usuários. No outro modelo, isso é possível também, mas existem mais combinações possíveis e isso é bom.

Pelo contrário. A Pessoa do tipo projetista tem um usuário associado que administrador. Ele ela é ambas as coisas.

Claro. O usuário associado à pessoa pode ter quantos e quais papeis de segurança forem necessários, incluindo administrador.
É que vc precisa explicar - que ainda não explicou - se administrador é um conceito de sistema ou de negócio ( como se fosse um gerente). No primeiro caso o modelo que que lhes estou dando serve porque a responsabilidade como pessoa no mundo dos negócios e a responsabilidade no sistema está separadas e podem se relacionar ou não conforme necessário

Pessoas diferentes podem ser todas administrador. Basta que o usuários que lhes está associado o seja.

Acho que não é assim tão complicado.
O problema é que vc está tentando usar um modelo de herança onde ele não cabe. Eu sei que nas escolas por ai se ensina herança assim e parece que no mundo real vc vai modelar assim, mas não.
Vc pode até usar herança com hibernate e jpa para dizer que uma pessoa de um certo tipo tem mais campos que a pessoa padrão, mas não pode misturar com o conceito de usuário e administrador.

Pensando aqui, administrador, neste caso é um conceito de negócio no meu ponto de vista, você pode me ajudar…
Uma pessoa no sistema terá privilégio para administrar, pessoas, projetos e tarefas. Isso ao meu ver, é um conceito de negócio.

*Se é que entendi direito o conceito de Administrador Negocio, Administrador Sistema.

Administrador Negocio : pessoa que gerenciará - create, remove, update, delete - de pessoas, projetos e tarefas através do sistema
Administrador Sistema: um tipo de usuário (que não deixa de ser pessoa) - entrei em loop de pensamento #crash- com privilégio para realizar o CRUD das pessoas, projetos e tarefas.

[quote]
Acho que não é assim tão complicado.
O problema é que vc está tentando usar um modelo de herança onde ele não cabe. Eu sei que nas escolas por ai se ensina herança assim e parece que no mundo real vc
vai modelar assim, mas não.[/quote]

Sim, estou de total acordo com o que você disse. Aprendi que com herança seria tudo lindo, e estou vendo que não é como “imaginava”. Mas é bom reaprender de forma correta.

[quote]
Vc pode até usar herança com hibernate e jpa para dizer que uma pessoa de um certo tipo tem mais campos que a pessoa padrão, mas não pode misturar com o conceito de usuário e administrador. [/quote]

Modelei como herança no hibernate utilizando JPA 2.0, mas já estou pra mudar quando acabar a minha “aula” contigo.

Abraço

[quote=andrielc][quote]
Claro. O usuário associado à pessoa pode ter quantos e quais papeis de segurança forem necessários, incluindo administrador.
É que vc precisa explicar - que ainda não explicou - se administrador é um conceito de sistema ou de negócio ( como se fosse um gerente). No primeiro caso o modelo que que lhes estou dando serve porque a responsabilidade como pessoa no mundo dos negócios e a responsabilidade no sistema está separadas e podem se relacionar ou não conforme necessário
Pessoas diferentes podem ser todas administrador. Basta que o usuários que lhes está associado o seja.
[/quote]

Pensando aqui, administrador, neste caso é um conceito de negócio no meu ponto de vista, você pode me ajudar…
Uma pessoa no sistema terá privilégio para administrar, pessoas, projetos e tarefas. Isso ao meu ver, é um conceito de negócio.

*Se é que entendi direito o conceito de Administrador Negocio, Administrador Sistema.

Administrador Negocio : pessoa que gerenciará - create, remove, update, delete - de pessoas, projetos e tarefas através do sistema
Administrador Sistema: um tipo de usuário (que não deixa de ser pessoa) - entrei em loop de pensamento #crash- com privilégio para realizar o CRUD das pessoas, projetos e tarefas.
[/quote]

Leia bem o que vc escreveu. Vc deu a mesma definição. Se admim é o cara que realiza o crud, então é um conceito de sistema.
Administrador de Negócios seria um Gerente, um Diretor, alguém no topo da hierarquia que “administra” as outras pessoas. Isso pode até existir, mas não está no sistema.

Vc pode modelar com jpa usando herança, mas de Pessoa com Pessoa , nada mais. E apenas se ha campos que realmente vale a pena separar. Para o Usuário vc não precisa de diferentes tipos. Vc utiliza a tecnica dos roles que falei no inicio. Um usuário tem uma coleção de roles (e tem que ter pelo menos 1, ou não tem acesso ao sistema). Vc pode começar com 2 roles de segurança : User e Admin. O Admin tem mais poderes que o User que é o usuário normal. Na sua aplicação vc verifica se o usuário tem o role que se pretende. se não tem esconde o botão ou o link da ação.

outra coisa que vc vai descobrir é que as entidades não têm métodos além de get/set das propriedades.

[code]public interface ChefeEquipe extends Role {
//implementacao de funcoes da interface

}

@Entity
public class Pessoa {

Collection roles;

public T asRole(Class type){
if (ChefeEquipe .class.isAssignableFrom(type)){
if (!this.hasRole(ChefeEquipe .class)){
return null;
}
return new ChefeEquipe (){

                        // nested class com os gets do administrato que são lidos dos private de pessoa.
                }
       } else if ( ... ){

     } 

}
}[/code]

Este codigo é o que voce cita a ser usado? Seguindo a estrutura de interface para os tipos de Pessoa, , assim cada pessoa teria seus metodos particulares …
O Java nao deixa criar interface estendendo Role.

[code]public interface ChefeEquipe extends Role { //erro no Java

}[/code]

Ou seguir o modo de tipoPessoa - uma classe enum, talvez - e a classe Pessoa, desse modo Pessoa tera todos os métodos particulares dos tipos.

Como voce citou sobre Heranca, e voce pode ver no ultimo diagrama que enviei aqui, que utilizei heranca para modelar as tarefas, duas camadas ainda… creio que, agora isso é um crime com pena de morte. Voce poderia dar uma ideia/comentar de como poderia ser reformulado essa etapa?

Aqui uma breve explificacao.

[i]Pessoas podem participar de Projetos e Tarefas, todo Projeto tem Tarefas
Existem Tarefas Padrao, de Especificacao e Adicional.

Tarefas do tipo Padrao tem 4 fases bem definidas e sao ligadas exclusivamente ao Projeto.
Cada fase tem uma data de duracao, respeitando a data de inicio ate data final do projeto.

Um projeto pode ter tarefas de especificacao e tarefas adicionais.

Pessoa pode participar de tarefas, diretamente, como esta descrito la, mas somente de tarefas adicionais e especificacoes.
[/i]

Se houver qualquer duvida, explicarei melhor.

Muito obrigado novamente, abraco.

Vc teria que criar o tipo Role em um arquivo à parte.

Veja bem, não é realista pensar que iremos modelar seu sistema todo aqui. O que dá para lhe ensinar são as ferramentas e os conceitos. São sempre os mesmos. Aplica os mesmos conceitos que aplicou à pessoa, na tarefa.
Por isso que eu falei que seu modelo é conceptual. Conceptualmente aquilo seria assim. OO e tudo mais. Mas no mundo real não é tão simples.
O Projeto tem tarefas e as tarefas são de diferentes tipos. Logo, precisamos de um TipoDeTarefa. Um certo tipo pode ter uma ciclo de vida , etc… Vc sempre tem que pensar que seu modelo pode não ser util, ou seja, nem todos os modelos conceptuais podem ser implementados. Talvez vc precise de mais entidades que ajudem a melhorar o modelo. Por exemplo se todas as tarefas tiverem fases , então todas seria iguais, com a mesma estrutrua. E ai é só uma questão de saber quantas fases tem a tarefa baseado no seu tipo.

Isto é um traballho de imaginação. Abstração, sinteses. Repetido várias vezes até que seja aceitável. Quanto mais homogéneo for o modelo ( ou seja, quanto menos importante for o tipo) melhor. Porque na prática não será simples vc ter 3 tipos de tarefa que fazm 3 coisas diferentes. É melhor ter 3 tipos que fazem tudo igual o que elas fazem diferente são parametros, são propriedades a tarefa (composição) e não caracteristicas da tarefa (herança).

Se uma pessoa participa de tarfas então a tarefa tem uma lista de pessoas. Simples. Se a lista é vazia porque não são preciso pessoas para a terefa , tudo bem. A estrutura de dados suporta várias configurações. Mas se vc cria duas classes Tarefa A e B e uma tem pessoa e a outra não, começa a ficar esquisito. Vc terá tod a hora que controlar qual o tipo de classe que está usando , etc… às vezes precisamos disto, mas quanto mais puder evitar melhor. E para evitar seu modelo tem que ser mais robusto (robustez é a qualidade de poder ser usado para coisas para as quais não foi planejado.) Se o seu modelo de dados atende seu modelo conceptual , otimo, mas seria melhor se ele atender mais do que isso. Se vc restringe seu modelo a ser o que vc quer agora, mais tarde vc irá se arrepender. Deixe aberto e deixe o resto do sistema colaborar para controlar as regras. As regras não estão só nas entidades, estão nos serviços, nos validadores, nos repositorios , etc…

As ferramentas são sempre as mesmas

  1. desacoplar dados que não pertencem juntos e não pulverizar dados que vão juntos.
  2. usar o minimo de herança possível
  3. usar o máximo de composição possível.

A ideia é como peças de lego. Tenha poucas peças base e faça outras peças partindos das básicas. Não especialize (herança) as básicas. Para especializar as outras, componha-as de forma diferente a partir das mesmas bases. eu sei que isto é meio abstrato, mas modelagem é abstrato. É como uma linguagem, se vc não sabe as palavras fica dificil expressar o que quer dizer.

Leia mais sobre os principios SOLID e alguma coisa de desing patterns, mas especialmente não acredite que aquele boneco que vc desenhou é como eu sistema vai ser de verdade. Aquilo é só um conceito.

Mediante a sua idéia, vou comentar o que não entendi e mostrar a minha idéia para a implementacao do Role.

[code]public interface Role {
//id para cada tipo
public static final int PROJETISTA = 1;
public static final int CHEFE_EQUIPE = 2;
public static final int CHEFE_PROJETO = 3;
}

public interface ChefeEquipe extends Role {
//implementacao de funcoes da interface

}
public interface Projetistas extends Role {
//implementacao de funcoes da interface

}
public interface ChefeProjeto extends Role {
//implementacao de funcoes da interface

}

@Entity
public class Pessoa {

Collection roles; //Nao entendi o motivo de utilizar uma collection de Role… e não seria uma Collection ?

private boolean hasRole(Class<?> aClass) {  //a implementar, creio que seja para verificar na Collection... algo que não sei ainda..
    throw new UnsupportedOperationException("Not supported yet.");
}

public T asRole(Class type){ //o template para criacao " T" funciona no C# … no Java eu não se, pesquisei na internet e nao achei
if (ChefeEquipe.class.isAssignableFrom(type)){ //Verifica se type tem as caracteristicas de uma classe ChefeEquipe
if (!this.hasRole(ChefeEquipe .class)){ //Isso verifica se o objeto Pessoa “this” tem o papel de algum objeto que foi inserido em Collection ?
return null;
}
return new ChefeEquipe (){
//implementacao dos metodos da interface ChefeEquipe
//Aonde seria a implementacao do ChefeEquipe com “status” ADMIN? Aqui também?
}
} else if ( … ){

     } 

}
}[/code]

Administrador seria também uma interface estendida de Role ?

[quote] Administrador admin = pessoa.as(Role.ADMIN);
[/quote]

Obrigado mais uma vez.

[quote=andrielc]Mediante a sua idéia, vou comentar o que não entendi e mostrar a minha idéia para a implementacao do Role.
[/quote]

Achei que já tinhamos passado esta fase.
É uma única classe Pessoa e pronto. Sem interfaces!
No máximo vc pode ter alguns tipos de pessoa por causa do hibernate/jpa, mas senão, é uma classe só com todos os campos!

Essa classe pessoa tb tem um objeto da classe usuário.

Não complique com as interfaces. Achei que já tinha entendido que esse não é um modelo realista.

Não. Já havimaos determinado que Administrador é relativo ao Usuário e não à pessoa. Ok ?