胖模特和瘦控制器听起来就像创造上帝模特

我已经阅读了很多提倡 胖模特和瘦控制器方法的博客,尤其是。Rails 训练营。因此,路由器基本上只是找出对什么控制器调用什么方法,而所有的控制器方法只是对模型调用相应的方法,然后调出视图。所以我有两个不明白的顾虑:

  1. 控制器和路由器实际上并没有做很多不同的任务,除了仅仅调用基于路由的类似上帝模型的方法之外。
  2. 模特们做得太多了。发送电子邮件,创建关系,删除和修改其他模型,排队任务等。基本上,现在您已经拥有了类似于上帝的对象,它们应该完成所有可能与建模和处理数据有关的事情,也可能与此无关。

你的底线在哪里? 这难道不是落入了上帝的模式吗?

43249 次浏览

I think you can make a distinction between a single fat model (possibly named App or Application), and several fat models broken down into logical groups (Business, Customer, Order, Message). The latter is how I structure my apps, and each model roughly corresponds to a database table in a relational database or collection in a document database. These models handle all aspects of creating, updating, and manipulating the data that makes up the model, whether it is talking to the database or calling an API. The controller is very thinm responsible for little mor that calling the appropriate model and selecting a template.

If the "model" classes are implemented poorly yes, your concern is relevant. A model class shouldnt be doing Email (infrastructure tasks).

The real question is what does model in MVC imply. It isnt restricted to POCO classes with a few methods. Model in MVC means Data and Business logic. Treat it as a superset of classic core POCO models.

View ==== Controller ==== Model ---> Business Process layer --> Core models

Throw in Infrastructure assemblies and Data Access layers and use injection to hand that into the BPL then your a process is using MVC as intended.

BPL may invoke UoW / Respository patterns, and execute business rules and call Infrastructure features by way of injected Objects or interface patters.

So the recommendation to keep a controller skinny doesnt mean the "person" class in a classic Core model should have 50 methods, and call Email directly. You are right to think this is wrong.

The Controller May still be required to instantiate and inject Infrastructure classes into the BPL or core layer if called directly. There should be a business layer or at least classes orchestrating calls across Classic Object model classes. Well thats my "view" anyway ;-)

For generic take on MVC the wiki description http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

A Little Blog that talks about the "M" in MVC. http://www.thedeveloperday.com/skinny-controllers/

It might not be the best idea to look at Rails as a staple of MVC design pattern. Said framework was made with some inherent shortcomings (I kinda elaborated on it in a different post) and the community only just now has begun addressing the fallout. You could look at DataMapper2 development as the first major step.

Some theory

People giving that advice seem to be afflicted by a quite common misconception. So let me begin by clearing it up: Model, in modern MVC design pattern, is NOT a class or object. Model is a layer.

The core idea behind MVC pattern is Separation of Concerns and the first step in it is the division between presentation layer and model layers. Just like the presentation layer breaks down into controllers (instances, responsible for dealing with user input), views (instances, responsible for UI logic) and templates/layouts, so does the model layer.

The major parts that the model layer consists of are:

  • Domain Objects

    Also known as domain entities, business objects, or model objects (I dislike that latter name because it just adds to the confusion). These structures are what people usually mistakenly call "models". They are responsible for containing business rules (all the math and validation for specific unit of domain logic).

  • Storage Abstractions:

    Usually implemented using data mapper pattern (do not confuse with ORMs, which have abused this name). These instances usually are tasked with information storage-from and retrieval-into the domain objects. Each domain object can have several mappers, just like there are several forms of storage (DB, cache, session, cookies, /dev/null).

  • Services:

    Structures responsible for application logic (that is, interaction between domain objects and interaction between domain objects and storage abstractions). They should act like the "interface" through which the presentation layer interacts with the model layer. This is usually what in Rails-like code ends up in the controllers.

There are also several structures that might be in the spaces between these groups: DAOs, units of work and repositories.

Oh ... and when we talk (in context of web) about a user that interacts with MVC application, it is not a human being. The "user" is actually your web browser.

So what about deities?

Instead of having some scary and monolithic model to work with, controllers should interact with services. You pass data from user input to a specific service (for example MailService or RecognitionService). This way the controller changes the state of model layer, but it is done by using a clear API and without messing with internal structures (which would cause a leaky abstraction).

Such changes can either cause some immediate reaction, or only affect the data that the view instance requests from model layer, or both.

Each service can interact with any number (though, it's usually only a handful) of domain object and storage abstractions. For example, the RecogitionService could not care less about storage abstractions for the articles.

Closing notes

This way you get an application that can be unit-tested at any level, has low coupling (if correctly implemented) and has clearly understandable architecture.

Though, keep in mind: MVC is not meant for small applications. If you are writing a guestbook page using MVC pattern, you are doing it wrong. This pattern is meant for enforcing law and order on large scale applications.

For people who are using PHP as primary language, this post might be relevant. It's a bit longer description of the model layer with a few snippets of code.