0
I am developing an application for didactic purposes, end of semester college work, in this will do CRUD of the disciplines in a table in the bank already created, "DISCIPLINES", I thought about creating a list of processes, if the user wants to redo his changes, type crt+z, it is after making the changes and being sure of this, execute the changes. thus:
The user does a crud operation by the graphical interface, and after the changes, by clicking OK, executes the list of processes. follows the code of the methods that generates, deletes and executes the processes:
//Implentação da interface omitidos
@Override
public void setupEvents() {
//evento do botão deletar disciplina
btnDelete.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int rowIndex = tbListDisciplines.getSelectedRow();
int id = (int)tbListDisciplines.getModel().getValueAt(rowIndex, 0);
InvokerRemove delete = new InvokerRemove(id, new ControllerDiscipline());
queue.addProcess(delete);
lblAmountDisciplines.setText("" + tbListDisciplines.getRowCount());
model.remove(rowIndex);
}
});
//evento do botão alterar disciplina
btnEdit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int rowIndex = tbListDisciplines.getSelectedRow();
int id = (int)tbListDisciplines.getModel().getValueAt(rowIndex, 0);
String name = tfNameDiscipline.getText();
InvokerUpdateRefatorar update = new InvokerUpdateRefatorar(id, name, new ControllerDiscipline());
queue.addProcess(update);
System.out.println(name);
Discipline marca = new Discipline();
marca.setName(tfNameDiscipline.getText());
model.update(rowIndex, marca);
}
});
//evento que finaliza as alterações e executa os processos de crud.
btnOk.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
glassPanel.start();
queue.executeProcess();
model.clearlistRemoved();
Thread performer = new Thread(new Runnable() {
public void run() {
perform();
}
}, "Performer");
performer.start();
}
});
//evento do botão cancelar, e invoca o método sair.
btnCancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
quit();
}
});
//MouseListener para preencher o textField
tbListDisciplines.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int rowIndex = tbListDisciplines.getSelectedRow();
tfNameDiscipline.setText((String)tbListDisciplines.getModel().getValueAt(rowIndex, 1));
}
});
}
//outros métodos omitidos
If the user wants to undo the change, he clicks cancel (I’m still implemented a better way to do this, for example crt+z to undo the last change) code below:
@Override
public void quit() {
if(!model.isEmptyList()){
int confirm = JOptionPane.showConfirmDialog(this, "Deseja sair, as alterações feita não serão salvas ?",
"Desistir das alterações?", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);
if(confirm == JOptionPane.YES_OPTION) {
this.dispose();
model.clearlistRemoved();
}
} else{
this.dispose();
}
}
just for the sake of beauty I added a glassPane to simulate a very simple thing process.
In the matter of generating the list of processes I am using Pattern Command, create a List of processes, Queuesprocess, who will be responsible for receiving all "crud operations" follows the code:
/**
* Classe responsável por criar uma fila de processos, CRUD,
* remove processos da fila para casos de refazer as decisões anteriores
* e limpa a fila para os próximos processos.
* <br><br>
* Nome do projeto: MeOrganize <br>
* Integra ao pocote: utfpr.tsi.meOrganize.controller.impl<br>
* @author Vinicius Cavalcanti
* @since implementação da aplicação
* @version 1.0v 2016
*/
public class QueuesProcess {
private Queue<IECommand> process;
/**
* construtor inicializa a lista de processos
*/
public QueuesProcess() {
process = new LinkedList();
}
/**
* Método que adiciona processos a lista
* @param process - o processo que será adicionado a fila
*/
public void addProcess(IECommand process) {
this.process.add(process);
}
/**
* Método que remove um processo adicionado
* @param process - processo que será removido
*/
public void removeProcess(IECommand process) {
this.process.remove(process);
}
/**
* Método que limpa a lista para casos
* de sair da janela e cancelar as operações (CRUD)
*/
public void clearQueues() {
this.process.clear();
}
/**
* Método que executa as operações na fila e limpa a fila.
*/
public void executeProcess() {
for(IECommand command : this.process)
command.execute();
process.clear();
}
}
As I had said I am using Pattern command, so I created an Iecommand interface for the Invoker contract with just the execute command. Dry the code below:
/**
* Contrato da fila de comandos CRUD.
* <br><br>
* Nome do projeto: MeOrganize <br>
* Integra ao pocote: utfpr.tsi.meOrganize.controller<br>
* @author Vinicius Cavalcanti
* @since
* @version 2016
*/
public interface IECommand {
void execute();
}
And an abstract class for crud requests, I’m going to create a controller for each table, in this case I’m only showing from the disciplines, but there will be other entities, like the study agenda, the planning.
/**
* Classe abstrata responsável pelos pedidos de Crud
* para camada dao, antes de inserir faz uma busca no banco
* para verificar se a entidade já existe e retonar o resultado.
* <br><br>
* Nome do projeto: MeOrganize <br>
* Integra ao pocote: utfpr.tsi.meOrganize.controller.impl<br>
* @author Vinicius Cavalcanti
* @since implentação da aplicação
* @version 1.0c 2016
* @param <T> entidade
* @param <E> qual dao será utilizado.
*/
public abstract class Controller<T, E> implements IERegister<T, E>{
protected IEDAO dao;
protected IEEntity entity;
public Controller(IEDAO dao, IEEntity entity) {
this.dao = dao;
this.entity = entity;
}
/**
* Método responsável por pedir a camada dao a inserção
* na tabela da entidade.
* @return - retorna true se a inserção foi feita, false se não é o erro.
* @throws - erro se a entidade veio nula.
*/
public boolean add(String name) throws EntityNull {
this.entity.setName(name);
if(exists() == false) {
try {
dao.insert(entity);
} catch (EntityNull | ClassNotFoundException e) {
System.out.println("Não foi possivel adicionar ao banco porque:\n" + e.getMessage());
}
return true;
}
return false;
}
/**
* Método responsável por pedir a remoção da entidade da tabela.
* A remoção e feita por uma busca pelo id da entidade.
* @return - retorna true se a remoção foi feita, false se não é o erro.
* @throws - erro se a entidade veio nula.
*/
public boolean remove(int id) throws EntityNull{
try {
this.dao.remove(id);
} catch (EntityNull | ClassNotFoundException e) {
System.out.println("Não foi possível remover porque:\n" + e.getMessage());
}
return false;
}
/**
* Método responsável por pedir a camada dao a alteração na entidade.
* faz uma busca pelo id da entidade e pede a alteração.
* @throws - erro se a entidade veio nula.
*/
public void update(int id, String name) throws EntityNull{
this.entity.setId(id);
this.entity.setName(name);
try {
this.dao.update(entity);
} catch (ClassNotFoundException e) {
System.out.println("Não foi possivel atualizar a entidade no banco porque:\n" + e.getMessage());
}
}
/**
* Método que verifica se a entidade já existe na tabale.
* faz uma busca na tabela pela entidade
* @return true se a entidade já existe, falso se não.
*/
public boolean exists() {
ArrayList<IEEntity<T>> entitys = new ArrayList<>();
try {
entitys.addAll(dao.searchData());
} catch (ClassNotFoundException e) {
System.out.println("Não foi possivel fazer a busca no banco porque:\n" + e.getMessage());
}
for(IEEntity enti : entitys) {
if(entity.getName().equals(enti.getName())) {
JOptionPane.showMessageDialog(null, "Entidade já existe", "Erro no cadastro da entidade", JOptionPane.ERROR_MESSAGE);
return true;
}
}
return false;
}
}
/**
* Contrato de controller das classe que recebe os dados
* para envidar para a camada DAO para manipular os dados das entidadades
* do banco de dados.
* <br><br>
* Nome do projeto: MeOrganize <br>
* Integra ao pocote: utfpr.tsi.meOrganize.controller<br>
* @author Vinicius Cavalcanti
* @since implementação da aplicação
* @version 1.0v 2016
* @param <T> Entidade que será passado para camada DAO.
* @param <E> Dao que será utilizado para entidade.
*/
public interface IERegister<T, E> {
/**
* Método responsável para enviar a camada DAO a entidade para salvar
* @param obj a entidade
* @throws EntityNull exceção de entidade nula.
*/
boolean add(String name) throws EntityNull;
/**
* Método responsável para enviar a camada DAO a entidade, por parâmetro o id,
* que será deletado.
* @param id - O id da entidade
* @throws EntityNull exceção de entidade nula.
*/
boolean remove(int id) throws EntityNull;
/**
* Método que verifica se a entidade já existe ou não
* @param dao
* @param entity
* @return true para existe e false para não existe.
*/
boolean existsDiscipline(T dao, E entity);
/**
* Método responsável para enviar a camada DAO a entidade, por parâmentro o id,
* que será alterado.
* @param id - O id da entidade.
* @throws EntityNull exceção de entidade nula.
*/
void update(int id, String name) throws EntityNull;
}
Another class that inherits the methods of the abstract class to do the crud, in this case the disciplines.
/**
* Classe concreta responsável por gerenciar os pedidos de crud
* para camada dao.
* <br><br>
* Nome do projeto: MeOrganize <br>
* Integra ao pocote: utfpr.tsi.meOrganize.controller.impl<br>
* @author Vinicius Cavalcanti
* @since implementação da aplicação
* @version 1.0v 2016
*/
public class ControllerDiscipline extends Controller{
/**
* construtor que manda para super classe um
* entidade criada pelo dao.
*/
public ControllerDiscipline() {
super(new DisciplineDAO(), new DisciplineDAO().create());
}
/**
* Método que faz a inserção.
* @return true se inserção bem sucedida false se não.
* @throws - exceção se a entidade está nula
*/
public boolean add(String name) throws EntityNull{
return super.add(name);
}
/**
* Método que faz a remoção.
* @return true se remoção bem sucedida false se não.
* @throws - exceção se a entidade está nula
*/
public boolean remove(int id) throws EntityNull{
return super.remove(id);
}
/**
* Método que faz a alteração.
* @return true se alteração bem sucedida false se não.
* @throws - exceção se a entidade está nula
*/
public void update(int id, String name) throws EntityNull {
super.update(id, name);
}
/**
* Método que verifica se a entidade já existe.
* @return true se sim. false se não.
*/
@Override
public boolean existsDiscipline(Object dao, Object entity) {
return false;
}
}
Well explained the context. Now they see my doubt if I’m doing it right, because our teacher will evaluate the elegance of the code too, not just be working, the "system" work should be well written, with moderate use of Patterns and a good structure. I created a class for each crud (Invokeradd, Iinvokerremove, Invokerupdate) as you can see in the interface code, I create a remove, and instant in the queue.
btnDelete.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int rowIndex = tbListDisciplines.getSelectedRow();
int id = (int)tbListDisciplines.getModel().getValueAt(rowIndex, 0);
InvokerRemove delete = new InvokerRemove(id, new ControllerDiscipline());
queue.addProcess(delete);
lblAmountDisciplines.setText("" + tbListDisciplines.getRowCount());
model.remove(rowIndex);
}
});
That will popular the process queue. with only one method. I will post only add but, serves for all, only change is the parameters, I thought about making a load of methods exchanging the parameters not, whenever I add a new "method" I am breaking the principle (Openclose) of Solid?
You could advise me on a better implementation?
You seem to be violating the MVC standard in some places. For example, your abstract class
Controller
uses theJOptionPane
which is something that should only be in the view. Also, create the controllers within theActionListener
view is another violation as it is the controller that should control the view, not the other way around.– Victor Stafusa
I understood thanks for the tip, refactored, I did an if to return the error. in the view, as for actionListener, isn’t the controller expecting a view request? I kind of didn’t understand what you meant by the controller controlling the view...
– Marcus Vinicius
When you give a
new ControllerDiscipline()
within theActionListener
, that’s part of the view, you’re violating the MVC. This means that the view is creating the controller, which is the controller that should create the view. That is, you have to inject an instance of the controller into yourJFrame
(or something similar), and never cause yourJFrame
(or aActionListener
) be responsible for instantiating the view.– Victor Stafusa
The idea is that you create the model, create the controller, provide the model to the controller, and then the controller creates the views and connects it to the model. Having the controller create the model itself may be acceptable as well. What you can’t do is the view create the controller or the view create the model, or the model knows the controller or the view (the other way around), or the view does operations that change the model without the controller.
– Victor Stafusa
Ah understood, in this case, could make a class with a static method that returns a controller object?
– Marcus Vinicius
Until something better comes along, yes, you can.
– Victor Stafusa