胖模型/瘦控制器与服务层

我已经使用.Net 开发企业应用程序多年了 我的应用程序通常有一个域模型,其中包含映射到 SQLDB 表的实体。 我使用 Repository 模式、依赖注入和服务层。

最近我们开始在 MVC 3项目上工作,我们有一个关于在哪里放置逻辑的争论。 我遇到了瘦控制器/FAT 模型架构,并想知道服务层将如何适应

方案1-服务模式对话

控制器是瘦的,调用模型上的方法。模型“知道”如何从数据库加载自己并与存储库或服务对话。 比如 customerModel 有一个 Load (id)方法,可以加载 customer 和一些子对象,比如 GetContracts ()。

选项2-控制器与服务对话

控制器要求服务检索模型对象。加载/存储的逻辑等。在服务层中。该模型是一个纯实体模型,仅包含数据。

为什么选项1会是一个更好的选择,特别是当我们谈论企业应用程序时,我的经验告诉我要分离关注点,尽可能地保持模型和控制器瘦,并有专门的服务来处理业务逻辑(imcl)。数据库交互)

感谢所有关于良好资源的建议和参考。

26831 次浏览

Option 1: You could think that model == service. Model also IS the business layer.

Option 2 is an Anemic Domain Model anti-pattern. http://en.wikipedia.org/wiki/Anemic_domain_model

All of this depends on the intention and requirements of your application.

That said, here's my suggestion for "mid scale" (not a local restaurant, and not Twitter/Facebook) web applications.

  1. Lean Domain Modeling

    Dry POCO style objects, preferably ignorant to the MVC architecture of your web application to remain as loosely coupled from your particular implementation as possible.perhaps even class library repack-able for use in an external application, say a REST API via a WCF Web Service).

    "Model" in MVC most accurately means the model the Controller is aware of and thus the the model intended for the View.

    In smaller (often Tutorial) applications the entity models of your "Application/Domain Model Layer" are often the same instantiated objects the controller ships off to a View.

    In larger applications developers often employ the tenets of MVVM architecture and begin using separate View Model objects. The controllers often call middle-tier services that work with the unseen entities below. In this scenario, the M in MVC most accurately means the View Model.

  2. Robust Service Layer

    This does not mean obese logic, but well-written single purpose services. While coding your business logic in services outside of the model is a bit more "procedural" than it is pure "OOP", it helps a lot with loose coupling, testing, and flexible deployment (ex. n-tier deployment).

    In my personal practice, I code services both down at the data layer, which I consider my behavioral modeling of the POCO objects (persistence mechanics, low level validation, etc.), and higher level services (business/workflow function) up closer to the MVC mechanics.

  3. Lean Controllers

    I make sure my controller is merely the coach, in that it is neither the play (services) or the player (entity model or view model), but simply decides who plays what position and what play to make. My controllers do two things:

    1. Call services that interact with the entity/domain Models

    2. Prepare a View Model for the appropriate View.

    Even authenticated/authorized controller actions are done via injected services/attributes.


EDIT 1:

Keep in mind, that this does not mean your Entity/Domain Model is or must be anemic. ORMs, repositories and factories, validation or state mechanics are welcome. It only means for applications of moderate scale, the Model in MVC represents the model meant for the controller, to hand off to your View.

Hopefully this point will calm Fowler apostles who believe the anemic data model to be an anti-pattern. At the same time, it does reflect a slightly more procedural angle than OOP where it is more pure to include behavior in the modeled classes.

There is no "ultimate truth", but using this pattern you'll find it easy to build, test, and deploy your applications - while maintaining a lot of re-usability and scalability.


EDIT 2:

That said, even for modestly sized applications, over architecting (that a word nerds made up?) a system is much too common. For instance, wrapping an ORM with a repository pattern, and then writing services to use the repository... all this is good for separation of concern and such, but if your project doesn't require (and is not very likely to soon require) such things, don't build it. There is nothing wrong with skipping the repository all together, writing thin business services (ex. query classes) against an ORM, or even having your controller talk directly to it. It all depends on scale.


EDIT 3:

I wanted to note that this explanation and advice is for the context of server-side MVC architecture like ASP.Net, not for clent-side frameworks like Knockout or Backbone.

You need to know some more about MVC before we go ahead and discuss where to put everything. Well, if you want to follow the pattern. Otherwise you can stop reading now.

The pattern is very loosely defined. There is nothing that says how the controller, view or model should look like or how they should be structured. The pattern simply states that you should separate the parts and how they should interact with each other. So let's look at bit more about what they are (my interpretation).

MVC

Model The model can be anything. It can be a webservice, your repositories, your service classes or simply your domain models. The Model are everything that are used to get the information that you need. Consider the "Model" as a layer instead of just an single object.

Controller The controller is a glue. It takes the information from the Model and adapts it to the view and vice versa.

View The view should only render what the user sees.

Do note that you should not confuse the Model with View Models. Microsoft should really have named the "Model" folder "ViewModels" since that's what they are. I would not use information from the "Model" directly in the views. Failure to do so would mean that you have to change the Model if the View is changed and the other way around.

The answer

The model is not a view model but a layer. Everything in the model is used to fetch the information needed for the view. The controller takes that information and puts it into a single view model.

A single controller action might use one or several calls to the "Model" to be able to assemble the information needed by the view.

That means that your second option is the most correct when if you want to get an application which is easy to maintain and extend.

Do note that a service layer might not be needed. You can call the OR/M directly from the controllers. But if you find yourself duplicating code or getting fat controllers, simply move the logic to a service layer. Nothing but the controller will be affected by that change since you are using proper view models.

Option 2 is what's described as Fat Stupid Ugly Controllers architecture (Reference to author of this expression). This solution is generally against MVC spirit as it breaks separation of concerns.