0

I’m still a Computer Science student, and recently I’ve had to develop a project using the MVC pattern, but without having learned in depth about how it actually works. And it’s not the first time I’ve had to do this type of work. I tried looking for complete examples on GitHub and even read the original article, but Smalltalk-80 intimidated me a bit. I’m developing my project in Java, but I’m completely lost on what actually belongs in each layer and the best way to organize the code as a whole. I understand that the model should encompass entities, their business rules, and data persistence, just as the view should handle what will be shown to the user (GUI), and the controller would manage interactions between these two layers.

The problem is that my code has other elements, such as a Programa class that acts as the starting point of the code, a Arquivo class that handles everything related to manipulating CSV files, and a Global class that attempts to create a set of global variables. These would allow reading the file only once, managing the set of entities through it, and saving everything to the file at the end of the program. The code is still in its initial stages, and I can’t progress due to a lack of knowledge and examples. Has anyone who has worked with this pattern in Java or a similar scenario, without using frameworks, got any advice on how to structure the project correctly? I want to make it as organized as possible and avoid code repetition. I appreciate any help, and I can provide any relevant information. Here’s the link to the repository with more information: https://github.com/LucasDLMaciel/TrabalhoAPS/tree/main

1
  • 3
    This question is similar to: In an MVC Application, What Goes Where?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem.
    – Christophe
    Commented Nov 13 at 7:51

2 Answers 2

3

In short: Views send UI Events to Controllers, Controllers figure out from Events what to send to Models, and Models, once processed data from Controllers, let Views know data has changed.

The short story:

Views are UIs, Controllers are the ActionListeners, and Models are everything else. One major advantage is that you can then take the same model, give it to 2 different Views, and if one View changes, so can the other, reflecting the same change, or you can change how your View looks entirely without changing the underlying Model, or have the Model change and not have to change the UI. Controllers translate when the UI wants to do something into something that the Model can do with it, so that the View can update it's display based on what the Model has.

The long of it:

At least in my experience, the MVC style attempts to separate responding to UI specific events from the displaying of UI specific components with Controllers responding to UI specific events, but UI displays handled by the View, and the Controllers responding to UI events by essentially tossing them straight at the model, and not themselves returning anything.

To pull an example from your Menu.java class , for example, this:

this.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                Menu.this.Buscar.setFocusable(false);
            }
        });

Is a Controller - or rather, an in-line Controller (You can sometimes just have the method attached to the UI class, and just go this.addMouseListener(this); - sometimes called a "Delegate" or a "View-Controller" - when stuff like the above feels like one line that you really don't want to make a whole dedicated class for the Controller. It can work, but it can sometimes not be ideal, like here.). Everything after this.addMouseListener could be it's own dedicated class, that you then construct in here, and have it respond to the events.

I'm going to build off of it a little bit to show where this may be useful - I'm using Google Translate to identify that as a thing that indicates that you're searching for something in, for example, the stuff that you're storing in a .csv - we're going to make a Controller for this so that, if hypothetically you were to provide it different Views, you could still use the Controller for a different View.

So a Controller class would look like this:

import javax.swing.*;
import java.awt.event.MouseAdapter;

public class AreaController extends MouseAdapter
{
    private JTextArea thingToPullFrom;
    public AreaController(JTextArea buscar){
        this.thingToPullFrom = buscar;
    }

    public void mouseClicked(){
        this.thingToPullFrom.setFocusable(false);
    }
}

then Menu.java would do this:

this.addMouseListener(new AreaController(this.Buscar));

That's great, but it isn't doing anything with the Buscar information, and let's say that we want to use that to, as part of the View, display if we've found a Usario in the Global.java class. Instead of having everything know how to pull Usarios out, we might do this with a non-static Global.java class.

In Progama.java:

public final class Programa {
    public static void main(String[] args) {
        Global globalModel = new Global();
        try {
            Menu menu = new Menu(gloablModel);
        } catch (Exception e) {
            System.out.println("Erro! O usuário não existe!");
            System.exit(1);
        }

The in Menu.java, we'd do this:

public class Menu extends JPanel {

    private Global globalModel;

    public Menu(boolean darkTheme, Global globalModel) {
        this.globalModel = globalModel;
        this.darkTheme = darkTheme; 
        this.init();
    }

    public void init(){
       // Other init function stuff here
       this.addMouseListener(new AreaController(this.Buscar, globalModel));
    }

}

That's a little bit of refactoring here, and probably not the intended output we really want here, and you may just want to create the model another way, but then you can do this in the AreaController class:

import javax.swing.*;
import java.awt.event.MouseAdapter;

public class AreaController extends MouseAdapter
{
    private JTextArea thingToPullFrom;
    private Global globalModel;
    public AreaController(JTextArea buscar, Global globalModel){
        this.thingToPullFrom = buscar;
        this.globalModel = globalModel;
    }

    public void mouseClicked(){
        this.thingToPullFrom.setFocusable(false);
        globalModel.usarioExiste(this.thingToPullFrom.getText());
    }
}

And this way, the Global.java class would take the method from Usario.java, and instead of needing to pass in a List<Usario> every time, the Global.java could, hypothetically hold the list already.

Except that's...not going to update the UI at all - the usarioExite() method in Usario.java currently returns a boolean, and it's being essentially ignored by the Controller. But, in the MVC approach, that is the intended way of avoiding passing information back up the Controller - the Controller should not care what the Model is doing to get the thing it wants, especially if it's going to be multi-threaded, etc. It just wants to tell the model to take the data it got from the View (In this case, the JTextArea Buscar, and get the model to do something.

So instead, we're going to instead of using that, have a variable in Global.java that refers to a specific seleccionadoUsuario

In Global.java:

public final class Global {

    private static List<Usuario> usuarios;
    private static Usario seleccionadoUsuario;

    private Global() {
    }

    public static List<Usuario> getUsuarios() {
        if (Global.usuarios == null) {
            Global.usuarios = carregarUsuarios();
        }
        return Global.usuarios;
    }

    public void setSeleccionadoUsario(String nombreDeUsario){
        if(usarioExiste(nombreDeUsario)){
           seleccionadoUsario = null;// something here instead of null, to actually get the user.
        }else{
           selecciandoUsario = null;
        }
    }

    public getSeleccionadoUsario(){
        return seleciandoUsario;
    }
}

I'm going to leave the actual selecting of the usario/user to be a mystery in case this is meant to be the actual homework, and I don't know your requirements, but...

What that means is that, if you want to do something with the seleciandoUsario in the view, you would go globalModel.getSeleciandoUsario(), and then use that value in displaying it.

That still technically doesn't solve the fact that the Model is not sending information to the View, though there are at least a couple ways of doing that:

1.) Continuously polling on globalModel.getSeleciandoUsario() to see if it's not null, then add it to whatever you wanted to do;

2.) Using the Observer pattern via the Java Observer and Observable interfaces, and then using setChanged() in the model to indicate that any View attached as an Observer knows that something has changed.

In this way, your Global.java Model is doing a larger amount of the data, and probably interacting with the rest of your modelo classes, and your Controller only essentially says "You know how to do this method - do this thing, with the thing I've received", and your View only cares about "Do I need to present something new to the user? If not, I'm just waiting, and if something comes up, I know which Controller to bother."

EDIT: So, for example Progama.java could do this, hypothetically:

public final class Programa {
    public static void main(String[] args) {
        Global globalModel = new Global();
        try {
            Menu menu = new Menu(globalModel);
            Menu menu2 = new Menu(globalModel); // Anything you do in menu will affect data that menu2 uses, and vice versa. Well, once the Model -> View connection is done as discussed above.
        } catch (Exception e) {
            System.out.println("Erro! O usuário não existe!");
            System.exit(1);
        }
2

I’m completely lost on what actually belongs in each layer and the best way to organize the code as a whole.

You have come to a crucial realization: MVC is not a comprehensive software architecture.

The Model-View-Controller pattern is a user interface design pattern. I find it intuitive and well-defined for the controller and view, but the model becomes a dumping ground for everything else. As you've discovered, there is a whole lot of "everything else."

MVC is really aimed at enforcing separation of concerns for the user interface. Go further into your application than skin deep and you find yourself precisely where you are right now: confused.

There are lots of different kinds of logic needed to make a program of non-trivial size work:

  • Configuration and initialization logic
  • Dependency management
  • Use case coordination logic
  • Business logic
  • User input validation
  • Cross-cutting concerns like error handling, logging, and fault tolerance
  • Data access logic
  • Authentication and authorization
  • Integration with outside systems (which is similar to data access logic)
  • Display logic

The MVC pattern gives you good places to put use case management logic (controllers), business logic (models), and display logic (views). It does not prescribe where to put the other kinds of logic, because that is outside the scope of the design pattern.

Application architecture provides that broader organization you are looking for. There is no One True Architecture, however you will notice that "layers" become a common thread woven into the different architectural styles:

More generally, search for application architecture or software architecture patterns. The MVC design pattern is often used within other architectures, but MVC only covers the user interface portion of the application.

The problem is that my code has other elements, such as a Programa class that acts as the starting point of the code

We have a couple buzzwords for this: inversion of control, and composition root.

Inversion of control specifies that generic code or framework code is executed first, and then based on what the user is doing or requesting, delegate control to something more specific. This usually means everything has essentially one main entry point into your application. In your case, that is the Programa class.

a Arquivo class that handles everything related to manipulating CSV files, and a Global class that attempts to create a set of global variables. These would allow reading the file only once, managing the set of entities through it, and saving everything to the file at the end of the program.

None of this has anything to do with the MVC pattern, which is why you've found it difficult to place in your application. More generally this feels like data access logic. Sure, you could say this belongs in the model, but now you are just dumping stuff in there when it deserves its own spot in the application.

The global variables class is probably used more like configuration. Most developers consider global variables to be an anti-pattern. Configuration objects, and things like the Arquivo class become dependencies for other objects. Something in your system needs to know who needs what, and then it needs to wire all these objects together via dependency injection. This becomes your composition root.

The Programa class could serve as your composition root. In fact, inversion of control, dependency injection, and the composition root are so complimentary that you frequently see those things put into the same class. Your Programa class serves as the single point of entry for all use cases. It uses dependency injection to initialize controllers (including all the other objects it needs to collaborate with), and possibly wires up event handlers.

In summary, don't feel like every line of code you write needs to be an M, a V, or a C. Those main components need other objects to accomplish a use case. Those other objects won't necessarily fit neatly into MVC, but that shouldn't stop you from using them. When an object needs to collaborate with other objects, use dependency injection to promote looser coupling between components. There are lots of ways to organize code based on what that code does, so don't restrict yourself to putting code files in just the models, views, or controllers folders.

2
  • I would argue that Models being "everything else" still makes it better defined than Controllers - the core problem I've found in my experience is that, at least in UI code, the Controllers tend to be so tightly bound to the View that defined as they are, the Controller tends to be subsumed into the View. Though as I understand from your link to IoC, it's more clear in web frameworks like Spring than it is in GUI libraries like Swing? Commented Nov 19 at 8:01
  • 1
    @AlexanderThe1st, some frameworks glue the view and controller together as inseparable. That is a design choice, not a mandate by the pattern. The .NET MVC framework has a default view, but that can be easily overridden by passing a parameter with the name of an alternate view when returning from a controller. Commented Nov 19 at 11:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.