Generics

13/03/2010

Boa tarde     Observe que esta classe possui uma caracterisca que é comum a todas as outras   por exemplo ela possui metodos para incluir, excluir, alterar pegar a categoria que esta selecionada entre outros metodos . Caso eu queira fazer um cadastro de Marcas ou unidades de medida vou precisar de uma classe igualzinha esta porem a unica coisa que tenho que trocar é o tipo do objeto por exemplo de categoria para marca ou unidadeDeMedida.   Tem uma forma de tornar esta classe generica para que eu não precise ficar repetindo as mesmas coisas sempre, diminuindo assim a quantidade de código repetido?   public class CategoriaManagerModel {
 
 private JFrame frame;
 private CategoriaDao categoriaDao;
 private ArrayListModel<Categoria> categoriaListModel;
 private SelectionInList<Categoria> categoriaSelection;  private Action novoAction;
 private Action alterarAction;
 private Action excluirAction;
  public CategoriaManagerModel(){}    public CategoriaManagerModel(JFrame frame, CategoriaDao categoriaDao) {
  this.categoriaDao = categoriaDao;
  this.frame = frame;
  iniciaModelos();
  iniciaLogicaApresentacao();
 }    private void iniciaModelos() {
  categoriaListModel = new ArrayListModel<Categoria>(categoriaDao.listar());
  categoriaSelection = new SelectionInList<Categoria>((ListModel)categoriaListModel);   novoAction = new NovoAction();
  alterarAction = new AlterarAction();
  excluirAction = new ExcluirAction();
   }    private void iniciaLogicaApresentacao() {
  categoriaSelection.addPropertyChangeListener(
    SelectionInList.PROPERTYNAME_SELECTION,
    new ObservadorSelecaoCategoria());
  controlaHabilitacaoActions();
 }    // Operações das Actions *******************************    private void doNovo(ActionEvent e) {
  Categoria categoria = adicionarCategoria();
  categoriaSelection.setSelection(categoria);
 }  private void doAlterar(ActionEvent e) {
  alterarCategoria(e);
 }
 
 public int exibirMensagem(String mensagem, int tipo) {
  int opc = JOptionPane.showConfirmDialog(frame, mensagem, "Informação do Sistema", tipo);
  return opc;
 }    private void doExcluir(ActionEvent e) {
  if(0 == exibirMensagem("Excluir a categoria \n"+"["+getCategoriaSelecionada()+"]"+"?",      JOptionPane.YES_NO_OPTION))
   categoriaListModel.remove(getCategoriaSelecionada());
 }    // Gerenciando ***************************************    private Categoria adicionarCategoria() {
  Categoria categoria = new Categoria();
  boolean cancelado = abrirCategoriaEditor(categoria);
  if (!cancelado) {
   categoriaListModel.add(categoria);
   salvarCategoria(categoria);
   return categoria;
  }
  return null;
 }    private void alterarCategoria(EventObject e) {
  boolean cancelado = abrirCategoriaEditor(getCategoriaSelecionada());
  if (!cancelado)
   categoriaSelection.fireSelectedContentsChanged();
 }    private void salvarCategoria(Categoria categoria) { categoriDao.salvar(categoria);  }    private boolean abrirCategoriaEditor(Categoria categoria) {
  CategoriaEditorDialog dialog = new CategoriaEditorDialog(frame, categoria);
  dialog.abrir();
  return dialog.foiCancelado();
 }  private Categoria getCategoriaSelecionada() {
  return categoriaSelection.getSelection();
 }   
 // Métodos de Acesso ***********************************
 
 public ArrayListModel<Categoria> getCategoriaListModel() {return categoriaListModel;}
 public SelectionInList<Categoria> getCategoriaSelection() {return categoriaSelection;}
 public Action getNovoAction() {return novoAction;}
 public Action getAlterarAction() {return alterarAction;}
 public Action getExcluirAction() {return excluirAction;}
 public MouseListener getObservadorDuploClique(){return new ObservadorDouploClique();}
 public Action getListarCategoriasAction() {return listarCategoriasAction;}
 public Action getPesquisarPorIdAction() {return pesquisarPorIdAction;}
 public Action getPesquisarPorDescricaoAction() {return pesquisarPorDescricaoAction;}    // Actions **********************************************    @SuppressWarnings("serial")
 private class NovoAction extends AbstractAction {
  public NovoAction() {
   super("Novo\u2026");
   putValue(Action.MNEMONIC_KEY, Integer.valueOf('N'));
  }     @Override
  public void actionPerformed(ActionEvent e) {
   doNovo(e);
  }
 }  @SuppressWarnings("serial")
 private class AlterarAction extends AbstractAction {
  public AlterarAction() {
   super("Alterar\u2026");
   putValue(Action.MNEMONIC_KEY, Integer.valueOf('E'));
  }   @Override
  public void actionPerformed(ActionEvent e) {
   doAlterar(e);
  }
 }
 
 @SuppressWarnings("serial")
 private class ExcluirAction extends AbstractAction {
  public ExcluirAction() {
   super("Excluir");
   putValue(Action.MNEMONIC_KEY, Integer.valueOf('R'));
  }   @Override
  public void actionPerformed(ActionEvent e) {
   doExcluir(e);
  }
 }    // Observadores *************************************    private void controlaHabilitacaoActions() {
  boolean comSelecao = categoriaSelection.hasSelection();
  alterarAction.setEnabled(comSelecao);
  excluirAction.setEnabled(comSelecao);
 }    private class ObservadorSelecaoCategoria implements PropertyChangeListener {   @Override
  public void propertyChange(PropertyChangeEvent arg0) {
   controlaHabilitacaoActions();
  }
 }    private class ObservadorDouploClique extends MouseAdapter {   @Override
  public void mouseClicked(MouseEvent e) {
   if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e) && categoriaSelection.hasSelection())
    alterarCategoria(e);
  }
 }
}
Israel Barbosa

Israel Barbosa

Curtidas 0

Respostas

Henrique Weissmann

Henrique Weissmann

13/03/2010

Olá Israel,

uma solução para o seu problema é fazer com que a classe Categoria seja uma subclasse de uma classe de domínio sua genérica (de preferência abstrata).

Em seguida, tudo o que vocë precisaria fazer consiste em definir os métodos publicos da sua classe para aceitarem como parametro a classe raiz. Assim a mesma classe poderia executar as mesmas ações nos diferentes subtipos derivados.
GOSTEI 0
Israel Barbosa

Israel Barbosa

13/03/2010

Boa noite Henrique Mas se a classe Categoria extender uma outra classe eu não consigo trabalhar com Hibernate e se ela implementar uma interface como Serializable eu tambem terei problemas porque em alguns metodos por exemplo adicionarCategoria eu terei que criar um objeto novo e não tem como fazer a instanciação de uma interface. Como resolver este problema?     private Categoria adicionarCategoria(){          Categoria categoria = new Categoria();          boolean cancelado = abrirCategoriaEditor(categoria);          (if !cancelado){                     categoriaListModel.add(categoria);                     salvarCategoria(categoria);                     return categoria;          }          return null; }       Alem disso, o método abre um editor especifico, como resolver mais este problema?   private boolean abrirCategoriaEditor(Categoria categoria) { CategoriaEditorDialog dialog = new CategoriaEditorDialog(frame, categoria); dialog.abrir(); return dialog.foiCancelado(); }     Fiz algumas aterações e cheguei nisto,funciona mas na hora de instanciar esta classe eu tenho que fazer a instanciação de um Objeto e passa-lo em seu construtor por exemplo:   ManagerModel managerModel = new ManagerModel(frame, categoriaDao, * new Categoria()  * ); ManagerModel managerModel = new ManagerModel(frame, categoriaDao, * new Marca()  * );   Sendo que acredito que o ideal seria:   ManagerModel managerModel = new ManagerModel(frame, categoriaDao, * Categoria.class * ); ManagerModel managerModel = new ManagerModel(frame, categoriaDao, * new Marca.class * );   e tambem o metodo destacado parece meio estranho, não parece?   Da uma olhada geral nesta classe ve se vc encontra algo errado.       public abstract class ManagerModel<B> {
 
 private JFrame frame;
 private CategoriaDao categoriaDao;
 private ArrayListModel<B> categoriaListModel;
 private SelectionInList<B> categoriaSelection;
 private ValueModel valueHolder;  private Action novoAction;
 private Action alterarAction;
 private Action excluirAction;
  public ManagerModel(){}    public ManagerModel(JFrame frame, CategoriaDao categoriaDao, B bean) {
  this.categoriaDao = categoriaDao;
  valueHolder = new ValueHolder(bean);
  this.frame = frame;
  iniciaModelos();
  iniciaLogicaApresentacao();
 }
 
 public ManagerModel(JFrame frame, B bean) {
  valueHolder = new ValueHolder(bean);
  this.frame = frame;
  iniciaModelos();
  iniciaLogicaApresentacao();
 }  @SuppressWarnings("unchecked")
 private void iniciaModelos() {
  categoriaListModel = new ArrayListModel<B>();
  categoriaListModel.addAll((Collection<? extends B>) categoriaDao.listarCategorias());
  categoriaSelection = new SelectionInList<B>((ListModel)categoriaListModel);   novoAction = new NovoAction();
  alterarAction = new AlterarAction();
  excluirAction = new ExcluirAction();
    }  private void iniciaLogicaApresentacao() {
  categoriaSelection.addPropertyChangeListener(
    SelectionInList.PROPERTYNAME_SELECTION,
    new ObservadorSelecaoCategoria());
  controlaHabilitacaoActions();
 }  // Operações ****************************************  private void doNovo(ActionEvent e) {
  B categoria = adicionarCategoria();
  categoriaSelection.setSelection(categoria);
 }  private void doAlterar(ActionEvent e) {
  alterarCategoria(e);
 }
 
 public int exibirMensagem(String mensagem, int tipo) {
  int opc = JOptionPane.showConfirmDialog(frame, mensagem, "Informação do Sistema", tipo);
  return opc;
 }  private void doExcluir(ActionEvent e) {
  if(0 == exibirMensagem("Excluir a categoria \n"+"["+getCategoriaSelecionada()+"]"+"?", JOptionPane.YES_NO_OPTION))
   categoriaListModel.remove(getCategoriaSelecionada());
 }  // Gerenciando ***************************************       Aqui neste método eu não deveria fazer a instanciação do tipo da classe passada no construtor via reflection?      private B adicionarCategoria() {
  Object obj = valueHolder.getValue();
  Object obj2 = null;
  try {
   obj2 = obj.getClass().newInstance();
  } catch (InstantiationException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  B categoria = (B) obj2;
//  Categoria categoria = new Categoria();
  boolean cancelado = abrirCategoriaEditor(categoria);
  if (!cancelado) {
   categoriaListModel.add((B)categoria);
//   salvarCategoria(categoria);
   return (B)categoria;
  }
  return null;
 }              private void alterarCategoria(EventObject e) {
  boolean cancelado = abrirCategoriaEditor(getCategoriaSelecionada());
  if (!cancelado)
   categoriaSelection.fireSelectedContentsChanged();
 }  private void salvarCategoria(B categoria) {
  adicionarCategoria();
 }       Sera que é correto redefinir este método na subClasse ou tem jeito de torna-lo generico tambem? para isto criando um GenericEditorDialog(frame, tipoGenerico).    protected abstract boolean abrirCategoriaEditor(B bean);
// private boolean abrirCategoriaEditor(B categoria) {
//  CategoriaEditorDialog dialog = new CategoriaEditorDialog(frame, (Categoria) categoria);
//  dialog.abrir();
//  return dialog.foiCancelado();
// }          private B getCategoriaSelecionada() {
  return categoriaSelection.getSelection();
 }  // Pesquisando *****************************************  @SuppressWarnings("unused")
 private Categoria pesquisarPorId() {
  // TODO
  return null;
 }  @SuppressWarnings("unused")
 private List<Categoria> pesquisarPorDescricao() {
  // TODO
  return null;
 }
 
 
 // Métodos de Acesso ***********************************
 
 public ArrayListModel<B> getCategoriaListModel() {return categoriaListModel;}
 public SelectionInList<B> getCategoriaSelection() {return categoriaSelection;}
 public Action getNovoAction() {return novoAction;}
 public Action getAlterarAction() {return alterarAction;}
 public Action getExcluirAction() {return excluirAction;}
 public MouseListener getObservadorDuploClique(){return new  ObservadorDouploClique();}
 public Action getListarCategoriasAction() {return listarCategoriasAction;}
 public Action getPesquisarPorIdAction() {return pesquisarPorIdAction;}
 public Action getPesquisarPorDescricaoAction() {return  pesquisarPorDescricaoAction;}  // Actions **********************************************  @SuppressWarnings("serial")
 private class NovoAction extends AbstractAction {
  public NovoAction() {
   super("Novo\u2026");
   putValue(Action.MNEMONIC_KEY, Integer.valueOf('N'));
  }   @Override
  public void actionPerformed(ActionEvent e) {
   doNovo(e);
  }
 }  @SuppressWarnings("serial")
 private class AlterarAction extends AbstractAction {
  public AlterarAction() {
   super("Alterar\u2026");
   putValue(Action.MNEMONIC_KEY, Integer.valueOf('E'));
  }   @Override
  public void actionPerformed(ActionEvent e) {
   doAlterar(e);
  }
 }
 
 @SuppressWarnings("serial")
 private class ExcluirAction extends AbstractAction {
  public ExcluirAction() {
   super("Excluir");
   putValue(Action.MNEMONIC_KEY, Integer.valueOf('R'));
  }   @Override
  public void actionPerformed(ActionEvent e) {
   doExcluir(e);
  }
 }    // Observadores *************************************  private void controlaHabilitacaoActions() {
  boolean comSelecao = categoriaSelection.hasSelection();
  alterarAction.setEnabled(comSelecao);
  excluirAction.setEnabled(comSelecao);
 }  private class ObservadorSelecaoCategoria implements PropertyChangeListener {   @Override
  public void propertyChange(PropertyChangeEvent arg0) {
   controlaHabilitacaoActions();
  }
 }  private class ObservadorDouploClique extends MouseAdapter {   @Override
  public void mouseClicked(MouseEvent e) {
   if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e) && categoriaSelection.hasSelection())
    alterarCategoria(e);
  }
 }
}
                        
GOSTEI 0
Henrique Weissmann

Henrique Weissmann

13/03/2010

Oi Israel,

respondendo as suas dúvidas:

"Mas se a classe Categoria extender uma outra classe eu não consigo trabalhar com Hibernate e se ela implementar uma interface como Serializable eu tambem terei problemas porque em alguns metodos por exemplo adicionarCategoria eu terei que criar um objeto novo e não tem como fazer a instanciação de uma interface. Como resolver este problema?"
Na realidade você pode usar o Hibernate sem problemas. Isto porque o HIbernate ignora se a classe extende outra ou não se você adicionar as anotações dentro da sua classe.

Com relação à instanciação da interface, aqui também o problema pode ser resolvido adotando-se o padrão Factory, que será o responsável por criar uma nova instância para você de acordo com o caso em questão.

"Alem disso, o método abre um editor especifico, como resolver mais este problema?"

Criando uma classe do tipo Factory que seja responsável por identificar a situação específica e, em seguida, criar uma instância adequada para a situação.

O método que você cita poderia ser sobrescrito da seguinte forma:

private boolean abrirCategoriaEditor(Classebase categoria) { if (categoria != null && categoria instanceof Categoria) {
CategoriaEditorDialog dialog = new CategoriaEditorDialog(frame, categoria); dialog.abrir(); return dialog.foiCancelado();}// os demais casos seguindo a mesma lógica
}

GOSTEI 0
Devmedia

Devmedia

13/03/2010

Israel,
a resposta do consultor foi suficiente? Podemos encerrar o chamado?
GOSTEI 0
Israel Barbosa

Israel Barbosa

13/03/2010

Sim
GOSTEI 0
POSTAR