可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 Controller
:
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
?
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!
回答1:
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):
MVC Diagram http://java.sun.com/developer/technicalArticles/javase/mvc/images/Figure4.gif
Source, and a great article on MVC!
回答2:
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:
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.
回答3:
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.
回答4:
"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.
回答5:
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.
回答6:
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:
alt text http://www.blogjava.net/images/blogjava_net/marco/7342/o_2.JPG
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
回答7:
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!
回答8:
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.
回答9:
- 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.
回答10:
View
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