MVC on the command line

2020-05-27 02:06发布

问题:

I am looking into the MVC from a Command line point of view (not web and no framework).. nice and simple. the only thing that confuses me is the View part of this? (well it may not be the only but its the main one)

from the IBM site the view has the following definition

The view provides the presentation of the model. It is the look of the application. The view can access the model getters, but it has no knowledge of the setters. In addition, it knows nothing about the controller. The view should be notified when changes to the model occur.

So if i have the following:

Model

  • Person

View

  • EditPersonDetails

Controller

  • PersonController

My person controller could pass a person object to the EditPeronDetails view, however how does my view edit the person if it cannot access its setters, how can i edit the person?

Also does the view class only do one thing? ie can I have a Person View, which has methods for Create, View, Delete, edit the person

many thanks

bones

回答1:

Is it really necessary to apply a 3 letter acronym here? if you must:

  1. user sees the console screen, which shows the view (lines of texts)
  2. user types something on command line, which is an even from view
  3. controller gets the event, i.e. the user input
  4. controller does something accordingly, and updates the model (persons)
  5. controller tells the view to repaint, i.e. print some more lines.

psuedocode:

Person // model
   update();

View
   modelUpdated()
       println(Person.name); ...

Controller
     main()
         while( input = getInput() )
             person.update(...);
             view.modelUpdated();


回答2:

define an abstract yet simple MVC program as:

interface Model {
    public void setName(String name);
}

interface View {
    public String prompt(String prompt);
}

class Controller {

    private final Model model;
    private final View view;

    public Controller(Model model, View view) {
        this.model = model;
        this.view = view;
    }

    public void run() {
        String name;

        while ((name = view.prompt("\nmvc demo> ")) != null) {
            model.setName(name);
        }
    }
}

then use the Observer pattern (built-in since JDK 1.0, see here) in order to fill the concrete classes:

class Person extends Observable implements Model {

    private String name;

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String newName) {
        this.name = newName;
        setChanged();
        notifyObservers(newName);
    }
}

class TUI implements Observer, View { // textual UI

    private final BufferedReader br;

    public TUI(Reader reader) {
        this.br = new BufferedReader(reader);
    }

    public void update(Observable o, Object arg) {
        System.out.println("\n => person updated to " + arg);
    }

    public String prompt(String prompt) {
        try {
            System.out.print(prompt);
            return br.readLine();
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}

The main class, that is only responsible to build and connect together the components:

TUI view = new TUI(new StringReader("David\nDamian\nBob\n"));
Person model = new Person();
model.addObserver(view);
Controller controller = new Controller(model, view);
controller.run();

the ouput of this program is:

mvc demo> 
 => person updated to David

mvc demo> 
 => person updated to Damian

...


回答3:

I'm not sure to get how you transposed the concept of view on the command line but I'll try to answer.

My person controller could pass a person object to the EditPeronDetails view, however how does my view edit the person if it cannot access its setters, how can I edit the person?

It doesn't, the controller does. The view only "captures" new values and actions and send them to the controller which handles them and updates the model.

Also does the view class only do one thing? ie can I have a Person View, which has methods for Create, View, Delete, edit the person

A view can do multiple things. For example, a same form could be used to create, read and update a domain object (by create and edit, I mean capturing values and sending them to the controller). This is actually a very common pattern. But as I said, it's not the view that performs the logic, it's the controller that does.

So, to answer your question, I guess we can imagine having dedicated methods on the Person View to capture the user input and to handle communication with the controller, but not for the CRUD logic (I'm really wondering how you handle interactions with the user on the command line, it doesn't seem really handy for a CRUD application).



回答4:

I'm working on re-architecting a trivial CLI program and have asked a similar question to myself.

In researching this, it's apparent that MVC and its derivatives are commonly misused. To complicate things further, variations of MVC (Web MVC comes to mind) exist that don’t adhere to the almost-original Smalltalk-80 implementation and definition of MVC.

That said, I like dfa's answer with one caveat: the user input should be placed in the controller, not the view. His answer aligns more closely with the Dolphin Smalltalk MVP pattern than MVC.

"The Controller is a component which responds to user input such as data entry and commands issued from a keyboard or mouse. Its responsibility is to act as a bridge between the human and the application, allowing the user to interact with the screen and data." - source

As such, I would remove:

return br.readLine();

from the view and simply have the controller wait for input as follows:

public void run() {
    view.prompt("\nmvc demo> ");
    String name = br.readLine(); // assume the BufferedReader object is now in the controller
    model.setName(name);
}

To be honest, I have a hard time justifying this as necessarily better, but thought I would throw out there.