3

I've just finished up a project in which I created a visual simulation of the life cycle of an ARM instruction in a single cycle processor. I used the MVC pattern in this project and ran into a design crossroads when I thought about how I was going to handle a specific part of the data being passed between the model and the view.

In my diagram in the view, I have a set of lines drawn over the data paths of the processor, which I will highlight based on the step in the ARM life cycle I'm talking about (for example, if the current step is referencing two sources being passed to the ALU, the lines corresponding to those two sources will light up). For each step there is a textual explanation of what is going on, as well as a set of lines being highlighted.

Here is a gif of the view in action: enter image description here

It is simple to pass the textual data between the model and the view without violating encapsulation, however I was not sure how to handle the graphical data (the lines). I've worked with a similar design before in a course I took on OOP, and we were told to ignore the violation of encapsulation in this instance - what we did was we created a set of states which were passed from the view to the model, updated, and sent back to the view.

It seems to me that this solution could be detrimental in a real-life situation due to arising bandwidth issues between the server and the client (passing relatively large data objects back and forth for any change of state in the view). Also, if I used this solution I would also be violating a basic tenant of the MVC pattern - keeping the view and the model entirely separate. If the view were to pass its line objects to the model, the model would know exactly how it's data was being implemented.

For my project I decided to stick with accepted programming practices and preserve encapsulation by making the concrete classes in the model send string objects to the controller that represented a certain set of lines. The controller would translate this string into a pre-initialized set of line segments and activate them (it would also deactivate line segments not mentioned). This solution, however, seems to me to be messy and didn't seem to scale very well because the controller would need to create a new set of lines and map it to any new possible string being sent from the model.

Here is a snippet of my controller code:

private Map<String, HashSet<Line>> lineSet;    

public void initController(){
    //groups of line objects initialized...
    HashSet<Line> ctrlIn = new HashSet<>();//a set of lines that will be mapped to a string
    ctrlIn.add(instrH);
    ctrlIn.add(cond);
    ctrlIn.add(op);
    ctrlIn.add(funct);
    ctrlIn.add(rd);
    ctrlIn.add(instrV1);

    lineSets.put("CtrlIn", ctrlIn);//maps the string expected from the model to the set of lines in the view
    
    ...
}

public void updateLines(ArrayList<String> s){//called by the model to update states of line objects
  activateLines(s);
 }

//helper function for handling lines, called by the updateLines function above
 public void activateLines(ArrayList<String> s){
   for(Line l: currLine)//currline is the current set of displayed line objects
       l.setVisible(false);
   for(String set : s){
     HashSet<Line> c = lineSet.get(set);
     for(Line l : c){
       currLine.add(l);
       l.setVisible(true);
     }
   }
 }

Here is some code from my implementing classes in the model:

//`step` is a ArrayList<String> that contains the set of steps in order for the instruction
step.add("Step 1: Step description here...");

//creates an ArrayList<String> object to hold all strings representing lines that should be displayed in the view (translated by the controller)
ArrayList<String> step1 = new ArrayList<>();
step1.add("CtrlIn");
//more strings added to `step1`...

lines.add(step1);//an array of strings is added to an outer array, corresponding to step 1

An index keeps track of the current step and returns two pieces of data to the controller: the description of the step from the step arraylist object, and an arraylist of string objects (corresponding to a set of line objects in the view) from the lines arraylist object. The controller displays the textual data to a textbox, and then uses lineSets.get(String s) to return the set of line objects mapped to the string returned by the model, and activates all lines in the set.

Violating encapsulation here seems like it might work better for my case because it would scale better. Neither the controller nor the concrete classes in my model would need to do much heavy lifting if they were both on board with what was going on in the view. I could inject references of the line objects in the view to the concrete classes in my model. When the view requests a change of state (next step), the model could just pass the set of lines to be displayed - the controller could skip translating the response from the model and just update the state of the lines in the view.

Was I correct in opting to preserve encapsulation in my design, or could an exception be made to handle the data alternatively, for example in the way I described above? Ultimately, what is the most correct way to handle the line object data in this situation, in accordance with accepted programming practices?

I tried to limit the amount of raw code to save space - let me know if there is any pertinent code related to the question that I should include.

Thank you for any advice.

1
  • I might be a bit slow here, but could you explain why it would break encapsulation for the model to parse the actual lines to the controller? I get the performance argument, and you are probably right about the encapsulation, I just don't see it at the moment. Jan 23, 2017 at 8:27

1 Answer 1

5

I like the current design.

It seems to me that this solution could be detrimental in a real-life situation due to arising bandwidth issues between the server and the client (passing relatively large data objects back and forth for any change of state in the view).

Meh, don't worry about performance problems until they are real problems. Instead write readable code that makes tweaking performance when needed later easy.

if I used this solution I would also be violating a basic tenant of the MVC pattern - keeping the view and the model entirely separate. If the view were to pass its line objects to the model, the model would know exactly how it's data was being implemented.

The model shouldn't know view details. What this means exactly is easiest to understand if you imagine you have two views. One view like you have, all graphical and what not, and a second view that say just types out what lines are lit up. By having two completely different views to manage it should become clear what the model doesn't care about. The model should be kicking out data either can use and nothing neither can use. The model shouldn't know what the x and y cords of the lines are. It should just know which lines are lit up. That's not a big bunch of data moving around.

I can even imagine a third view made of GUI controls like check boxes that get ticked when the line they represent is lit up. Adding these views shouldn't cause you to touch a single line of model code.

If your question is simply, "can I ignore all that?", then sure. Go ahead. Just please don't call it MVC.

Your Answer

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

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