开发者

Understanding the MVC Pattern

I am having some trouble understanding the MVC Pattern. I do understand we are trying to decouple the GUI from the business logic, although I'm having problems understanding how.

From what I understood, the View, is what the user sees. So it generally is the window/form. The Controller is inbetween the View and the Model. The Controller will make the data "flow" in both directions. It will also persist state when needed (if I have a wizard with 5 steps, it is the Controller's responsability to ensure they are made in the correct order, etc). The Model, is where the core of my application logic lives.

Is this view correct?

To try to turn this into something more meaningful, I'll try to sketch out a simple example with WinForms(no ASP.NET or WPF, please! - to the java crowd, from what I come to understand, Swing works in a similar way to WinForms!), to see if I get it right, and I'll raise the questions I always come to while doing it.


Let's assume I have a model that contains just a class (just to make it easier. I know it will make the example look dumb but its easier this way):

class MyNumbers {
    private IList<int> listOfNumbers = new List<int> { 1, 3, 5, 7, 9 };

    public IList<int> GetNumbers() {
        return new ReadOnlyCollection<int>(listOfNumbers);
    }
}

Now it's time to make my Controlle开发者_如何学Gor:

class Controller
{
    private MyNumbers myNumbers = new MyNumbers();

    public IList<int> GetNumbers() {
        return myNumbers.GetNumbers();
    }
}

The View should just have a ListBox that has as items all the numbers retrieved in MyNumbers.

Now, the first question arises:

Should the Controller be responsible for creating MyNumbers? In this simple case, I think its acceptable(as MyNumbers will do exactly the same, no matter what, and has no associated state). But let's assume I would want to use for all the different Controllers my app has the same instance of MyNumbers. I would have to pass to this Controller(and all others that need it) that instance of MyNumbers that I want to use. Who is going to be responsible for that? In this WinForms examples, would that be the View? Or would that be the class that creates the View?

Turning the question around: what is the order of instantiation of these 3 parts? What is the code that the "owner" of the MVC called to create it? Should the Controller create both the View and Model? Should the View instantiate the Controller and the Controller the Model?

Second question:

How is the main method supposed to look like, assuming I only want my application to have the Use Case this Controller portrays?

Third:

Why does in the following MVC diagram, the View have an arrow to the Model? Shouldn't the Controller be always the bridge between both View and Model?

Understanding the MVC Pattern


I'll have one or two more questions, but they probably will make more sense asked after I understand this first detail. Or maybe after I understand that first question all the others tear apart.

Thanks!


The easiest way to get a handle on MVC is to use it in a framework that enforces it, that being said..

  • The Model interacts with the datasource (DB or whatever) and gives you access to your data.
  • The View interacts with the outside world, it receives input from somewhere and hands off the data to the Controller it also listens to the Controller to make sure its displaying the correct data.
  • The Controller is where all the magic happens; the Controller manipulates data, pushes events, and handles changes in both directions (to/from the View and to/from the Model).

This diagram is very helpful (it makes much more sense than Wikipedia's):

Understanding the MVC Pattern

Source, and a great article on MVC!


As for the criticism within my post I thought I would give a post on how i tend to create an MVC Pattern in PHP

Within PHP i spit the framework up into several sections, of witch some are the normal when it comes to MVC.

Primaries:

  • Controller
  • Model
  • View

Secondariness - ModelLayer

  • ViewLoader
  • Library
  • ErrorLayer

Within the controller I usually allow all access the secondary layers and the View and Model from Primary.

Here's the way I would structure it

|---------|       |------------|       |------------|
| Browser | ----> | Controller | ----> |   Model    |
|---------|       |------------|       |------------|
     |                  |   |                |
     |                  |   |----------------|
     |                  |
     |            |------------|
     -------------|    View    |
                  |------------|

From my diagram I usually bypass the View <-> Model connection and do a Controller <-> Model and then the link from Controller <-> View assigns the data.

Within my framework I tend to create a object storage system so that i can easily fetch objects and so forth. an example of my object storage is like so

class Registry
{
   static $storage = array();

   public static function get($key)
   {
       return isset(self::storage[$key]) ? self::storage[$key] : null;
   }

   public static function set($key,$object)
   {
       self::"storage[$key] = $object;
   }
}

Somewhat more advanced by that's the outline, so with this when I first initialize objects i store them like Registry::set("View",new View()); so that there always accessible.

So within my controller witch is the base controller i create several magic methods __get() __set() so that any class that extends the controller I can easily return teh request for example:

abstract class Controller
{
   public function __get($key)
   {
       //check to make sure key is ok for item such as View,Library etc

       return Registry::get($key); //Object / Null
   }
}

And the user controller

class Controller_index extends Controller
{
    public function index()
    {
       $this->View->assign("key","value"); // Exucutes a method in the View class
    }
}

The model will also be placed into registry but only allowed to be called from ModelLayer

class Model_index extends ModelLayer_MySql
{
}

or

class Model_index extends ModelLayer_MySqli
{
}

or filesystem

class Model_file extends ModelLayer_FileSystem
{
}

so that each class can be specific to the storage type.

This is not the Traditional type of MVC Pattern but it can be called Adoptive MVC.

Other objects such as the View Loader should not be placed into registry as there not specifically for the users interests but used by other entites such as View

abstract class ViewLoader
{
   function __construct($file,$data) //send the file and data
   {
       //Include the file and set the data to a local variable
   }

   public function MakeUri()
   {
       return Registry::get('URITools')->CreateURIByArgs(func_get_args());
   }
}

as the template file is being included in the View loader and NOT the View class it separates the user methods from teh system methods and also allows methods to be used within the views themselves for general logic.

Example of template file.

<html>
   <body>
      <?php $this->_include("another_tpl_file.php"); ?>
      <?php if(isset($this->session->admin)):?>

          <a href="<?php echo $this->MakeUri("user","admin","panel","id",$this->session->admin_uid) ?>"><?php echo $this->lang->admin->admin_link ?></a>

      <?php endif; ?>
   </body>
</html>

I hope my examples help you understand that little bit more.


Answer to the third question:

When the model changes, it notifies the view, then the view gets the data from the model using its getters.


"From what I understood, the View, is what the user sees. So it generally is the window/form. The Controller is inbetween the View and the Model. The Controller will "handle" data in both directions. It will also persist state when needed (if I have a wizard with 5 steps, it is the Controller's responsability to ensure they are made in the correct order, etc). The Model, is where the core of my application logic lives."

This is almost correct. The controller doesn't persist data. It calls a service that persists data. The reason is, persisting data is never just a call to save. You might want to do validation checks on the data to make sure it is sane according to your business needs. You might want to do some authentication to make sure the data can be saved by a user. If you do that in a service, then you have a nice bundle of functionality that you can use over and over again, say for a webapp and a web service. If you do it in a controller, say for a web app, when you go to write your web service you will have to refactor and/or duplicate code.

In response to your comment "I am not sure I totally understood your point. Does the Controller check UI input, or is the Model that does it?"

You controller should only control which business functionality paths get executed. Thats its. Controllers should be the easiest part of the code to write. You can do some validation on the gui (i.e. view, e.g. like making sure email addresses are properly formatted, text inputs dont exceed maximums), but the business layer should also validate the input -- for the reason I mentioned earlier, that when you start standing up more endpoints, you don't have to refactor.


Should the Controller be responsible for creating MyNumbers?

I would say 'definitely not.'

If the MVC pattern is designed to decouple the M, V, & C elements, how can this work if the C simply instantiates the M with new MyNumbers()?

In Java, we would use something like the Spring Framework here. You need a way to express the dependency relationship -- or rather the details of how it gets fulfilled -- in a configuration file or other suitable place (i.e. not in compiled code).

But there is another element to this issue: you probably shouldn't define the myNumbers variable (inside C) with the concrete, runtime type you intend to use. Use an interface or an abstract class, and leave it open as to what the actual runtime type is. This way, in the future you can re-implement the IMyNumbers interface to satisfy emerging requirements (those you don't know today) and your C component will continue to work perfectly, none the wiser.


This is from Java, but hopefully it will help.

For the main:

public static void main(String[] args) 
{
       MyNumbers myNums = new MyNumbers();  // Create your Model
       // Create controller, send in Model reference.      
       Controller controller = new Controller(myNums); 
}

Your controller needs a reference to your model. In this case, the controller actually creates all the Swing components. For C#, you may want to leave the form initialization here, but the View/Form needs a reference to the Model (myNums) and the Controller (controller). Hopefully some C# people can help on this front. The View also needs to register as an Observer of the Model (see Observer Pattern).

Here is the constructor I have (adjusted for your case):

public NumberView(Controller controller, MyNumbers myNums)
{
      this.controller = controller; // You'll need a local variable for this
      this.myNums = myNums; //You'll need a local variable for this
      myNums.registerObserver(this); // This is where it registers itself
}

The View passes the work to the Controller to handle the user's actions (buttons, whatever). The Controller decides what to call/do in the Model. In general, the Model then does something and changes its state(maybe more numbers in your list. Whatever it does). At the point, the Model will let its Observers know it has changed and to update themselves. Then the View goes and gets the new data and updates itself. That is why the Model and View talk (your 3rd question).

So the Model will have:

public void notifyObservers()
{
    for (Observer o: observers)
    {
        o.update();  // this will call the View update below since it is an Observer
    }
}

So in the View, you'll have something like this:

public void update()
{
    setListBox(myNums.getNumbers());  // Or whatever form update you want
}

Hope that helps. I know it is Java, but the concept still applies. You'll have to do a little reading on the Observer pattern to fully get it. Good luck!


I will try to answer this from a relatively less technical stand for what it's worth. I'll try walk through a general example.

Controller controls what view is used. So, say, if you are writing to the page the controller will direct you to the input view (say) while if you are reading the same page it will direct you to it's success view (say).

After one writes to the page the controller will pass those parameters to the relevant model where the logic pertaining to what has to be done with them resides. If there is as error then the controller will direct you to the error view.

My knowledge is based on my one month experience with Agavi. Hope this helps.


Why does in the following MVC diagram, the View have an arrow to the Model? Shouldn't the Controller be always the bridge between both View and Model?

It is the MVC model 2. You can see it usually in Java enterprise application where CONTROL does the business as well as processes data from/to MODEL and choose which VIEW to render back to client. When rendering to client, VIEW will use data from MODEL:

Understanding the MVC Pattern


(source: blogjava.net)

Here is an example how to access data from a JSP(VIEW) file which a bean (MODEL):

class Person {String name;} // MODEL
My name is ${bean.name}     // VIEW


  • View draws the model and represents it to the user
  • Controller handles the user input and translates them to the modifications into the model
  • Model holds the data and modification logic

There's no point translating it into code. You won't get it correct straight out anyway.


View

  • user interface / responsible with input output / some validation / needs to have a way to notify outside world of UI level events

  • knows only about the model

Model

  • data structure / represents the data that is presented / should not contain business logic (maybe only some data/structure validation at most)
  • knows only about himself (think of a Person class that has only Name and Age)

Controller

  • is responsible for business logic / it crates Views and glues the respective models onto them / has to be able to respond to View events / accesses other layers of the application (persistence / external services / business layers etc.)

  • knows everything (at least View and model) and is responsible of gluing everything together

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜