“业务逻辑层”在哪里?适合 MVC 应用程序吗?

发布于 2024-10-09 11:22:04 字数 603 浏览 0 评论 0 原文

首先,在有人尖叫之前,我很难用一个简单的标题来总结它。另一个标题可能是“领域模型和 MVC 模型有什么区别?”或“什么是模型?”

从概念上讲,我将模型理解为视图和控制器使用的数据。除此之外,对于模型的构成似乎存在很多不同的意见。什么是领域模型,与应用程序模型,与视图模型,与服务模型等。

例如,在最近我问到的有关存储库模式的问题中,我被直白地告知存储库是模型的一部分。然而,我读过其他观点,认为模型应该与持久化模型和业务逻辑层分开。毕竟,存储库模式不是应该将具体的持久性方法与模型分离吗?其他人说Domain模型和MVC模型之间有区别。

让我们举一个简单的例子。 MVC 默认项目中包含的 AccountController。我读过一些意见,认为所包含的帐户代码设计不佳,违反了 SRP 等等。如果要为 MVC 应用程序设计一个“正确的”会员模型,那会是什么?

您如何将 ASP.NET 服务(成员资格提供程序、角色提供程序等)与模型分开?或者你根本愿意吗?

在我看来,模型应该是“纯粹的”,也许带有验证逻辑......但应该与业务规则(验证除外)分开。例如,假设您有一条业务规则,规定创建新帐户时必须向某人发送电子邮件。在我看来,这并不真正属于模型。那么它属于哪里呢?

有人愿意阐明这个问题吗?

First, before anyone screams dupe, I had a hard time summarizing it in a simple title. Another title might have been "What is the difference between a domain model and MVC model?" or "What is a model?"

Conceptually, I understand a Model to be the data used by the views and controller. Beyond that, there seems to be a great deal of differing opinions on what makes up the model. What's a domain model, versus an app model, vs a view model, vs a service model, etc..

For example, in a recent question I asked about the repository pattern, I was told point blank that the repository is part of the model. However, I have read other opinions that the model should be seperated from the persistence model and the business logic layer. After all, isn't the Repository pattern supposed to decouple the concrete persistence method from the model? Other people say there is a difference between the Domain model and the MVC model.

Let's take a simple example. The AccountController that is included with the MVC default project. I've read several opinions that the Account code included is of poor design, violates SRP, etc.. etc.. If one were to design a "proper" Membership model for an MVC application, what would that be?

How would you seperate the ASP.NET services (Membership provider, role provider, etc..) from the model? Or would you at all?

The way I see it, the model should be "pure", perhaps with validation logic.. but should be seperate from business rules (other than validation). For example, let's say you have a business rule that says someone must be emailed when a new account is created. That doesn't really belong in the model in my view. So where does it belong?

Anyone care to shed any light on this issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

抽个烟儿 2024-10-16 11:22:04

我所做的方式 - 我并不是说它是对还是错,是拥有我的视图,然后是适用于我的视图的模型。这个模型只有与我的观点相关的内容——包括数据注释和验证规则。控制器仅包含用于构建模型的逻辑。我有一个服务层,其中包含所有业务逻辑。我的控制器调用我的服务层。除此之外是我的存储库层。

我的域对象是单独存放的(实际上是在他们自己的项目中)。他们有自己的数据注释和验证规则。我的存储库会在将域中的对象保存到数据库之前对其进行验证。因为我域中的每个对象都继承自内置验证的基类,所以我的存储库是通用的并验证所有内容(并要求它继承自基类)。

您可能会认为拥有两组模型是代码的重复,并且在某种程度上确实如此。但是,在某些完全合理的情况下,域对象不适合视图。

典型的例子是使用信用卡时 - 我在处理付款时必须要求提供 cvv,但我无法存储 cvv(这样做会被处以 50,000 美元的罚款)。但是,我还希望您能够编辑您的信用卡 - 更改地址、姓名或到期日期。但您在编辑时不会给我号码或 cvv,我当然不会在页面上以纯文本形式显示您的信用卡号。我的域具有保存新信用卡所需的这些值,因为您将它们提供给我,但我的编辑模型甚至不包含卡号或 cvv。

这么多层的另一个好处是,如果架构正确,您可以使用结构图或另一个 IoC 容器并交换各个部分,而不会对您的应用程序产生不利影响。

在我看来,控制器代码应该只是针对视图的代码。显示这个、隐藏那个等等。服务层应该容纳应用程序的业务逻辑。我喜欢将所有内容集中在一个地方,这样可以轻松更改或调整业务规则。存储库层应该相对愚蠢 - 缺乏业务逻辑,仅查询数据并返回域对象。通过将视图模型与域模型分离,您在自定义验证规则方面拥有更大的灵活性。这也意味着您不必将每条数据转储到视图中的隐藏字段中,并在客户端和服务器之间来回推送(或在后端重建它)。然后,您的视图模型将仅包含与视图相关的信息 - 并且可以将其自定义为具有用于视图逻辑或计数或枚举的布尔值,以便视图本身不会被复杂的逻辑语句弄乱,例如

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

虽然一切似乎都分散了,过度分层,它以这种方式构建是有目的的。完美吗?并不真地。但我确实更喜欢它,而不是过去的一些从控制器调用存储库并将业务逻辑混合在控制器、存储库和模型中的设计。

The way I have done it - and I'm not saying it is right or wrong, is to have my View and then a model that applies to my view. This model only has what is relevant to my view - including data annotations and validation rules. The controller only houses logic for building the model. I have a service layer which houses all business logic. My controllers call my service layer. Beyond that is my repository layer.

My domain objects are housed separately (in their own project, actually). They have their own data annotations and validation rules. My repository validates the objects in my domain before saving them into the database. Because every object in my domain inherits from a base class which has validation built in, my repository is generic and validates everything (and requires it inherits from the base class).

You might think that having two sets of models is duplication of code, and it is to an extent. But, there are perfectly reasonable instances where the domain object is not appropriate for the view.

Case in point is when working with credit cards - I have to require a cvv when processing a payment, but I cannot store the cvv (it is a $50,000 fine to do so). But, I also want you to be able to edit your credit card - change of address, name, or expiration date. But you aren't going to give me the number or the cvv when editing it, and I certainly am not going to put your credit card number in plain text on the page. My domain has these values required for saving a new credit card because you give them to me, but my edit model doesn't even include the card number or cvv.

Another benefit to so many layers is that if architected correctly, you can use structuremap or another IoC container and swap out pieces without detrimentally affecting your application.

In my opinion, controller code should only be code targeted at the view. Show this, hide that, etc. The service layer should house the business logic for your app. I like having all of it in one place so it's easy to change or tweak a business rule. The repository layer should be relatively dumb - devoid of business logic and only query your data and return your domain objects. By separating the view models from the domain model, you have much more flexibility when it comes to custom validation rules. It also means you don't have to dump every piece of data into your view in hidden fields and push it back and forth between the client and server (or rebuild it on the backend). Your view model will then house only the information relevant to the view - and it can be customized to have bools for view logic or counts or enums so that the view itself isn't cluttered up with complicated logic statements like

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

While everything seems spread out and over-layered, it has a purpose for being architected this way. Is it perfect? not really. But I do prefer it to some past designs of calling repositories from the controller and having business logic mixed in the controller, repository, and model.

满地尘埃落定 2024-10-16 11:22:04

我经常想知道 MVC 元素到底如何适合传统的 Web 应用程序结构,其中包含视图(页面)、控制器、服务和数据对象(模型)。正如你所说,有很多版本。

我相信这种混乱的存在是由于上述广泛接受的架构,它使用“贫血领域模型”(所谓的)反模式。我不会详细介绍贫血数据模型的“反模式”(您可以查看我的解释此处(基于 Java,但与任何语言相关)。但简而言之,这意味着我们的模型只保存数据,业务逻辑放置在服务/管理器中。

但假设我们有域驱动架构,并且我们的域对象是预期的方式to be - 具有状态和业务逻辑。在这个领域驱动的视角中,事情就位了:

  • 视图是 UI,
  • 控制器收集 UI 的输入,调用模型上的方法,并向 UI 发送回响应,
  • 模型是我们的业务组件 - 保存数据,而且还具有业务逻辑。

我想这回答了你的主要问题。当我们添加更多层(例如存储库层)时,事情会变得复杂。通常建议它应该由模型中放置的业务逻辑来调用(因此每个域对象都有对存储库的引用)。在我链接的文章中,我认为这并不是最佳实践。事实上,拥有服务层并不是一件坏事。顺便说一句,领域驱动设计并不排除服务层,但它应该是“薄”的,并且仅协调领域对象(因此那里没有业务逻辑)。

对于广泛采用的贫乏数据模型范例(无论好坏),模型将是服务层和数据对象。

I too often wondered how exactly the MVC elements fit in a traditional web application structure, where you have views (pages), controllers, services, and data objects (model). As you said, there are many versions of that.

I believe the confusion exists because of the above stated, widely accepted architecture, which uses the "anemic domain model" (alleged)-anti pattern. I won't go into much details about the "anti-patternness" of anemic data model (you can look at an effort of mine to explain things here (Java-based, but relevant for any language)). But in short, it means that our model holds only data, and business logic is placed in services/managers.

But let's assume we have domain driven architecture, and our domain objects are the way they are expected to be - having both state and business logic. And in this domain-driven perspective things come into place:

  • the view is the UI
  • the controller gathers the inputs of the UI, invokes methods on the model, and sends back a response to the UI
  • the model is our business components - holding the data, but also having business logic.

I guess that answers your main questions. Things get complicated when we add some more layers, like the repository layer. It is often suggested that it should be invoked by the business logic placed in the model (and hence each domain object has a reference to a repository). In the article of mine that I linked I argue that this is not quite a best practice. And that in fact it is not a bad thing to have a service layer. By the way, domain-driven design does not exclude the service layer, but it is supposed to be 'thin', and only coordinating domain objects (so no business logic there).

For the anemic data model paradigm, which is widely adopted (for good or for bad), the model would be both the service layer and your data objects.

抱猫软卧 2024-10-16 11:22:04

在我看来,

模型 -

不应该包含业务逻辑,它应该是可插入的(类似WCF的场景)。它用于绑定视图,因此它应该具有属性。

业务逻辑 -

它应该放置在“域服务层”,它完全是单独的层。
另外,将在此处再添加一层“应用程序服务”。

应用程序服务与域服务层对话以应用业务逻辑,然后最后返回模型。

所以,
控制器将向应用程序服务请求模型,流程将如下所示:

    Controller->Application Services(using domain services)->Model

In my opinion,

Model -

Should not contain business logic, it should be pluggable(WCF like scenario). It is used to bind to view so, it should have properties.

Business Logic -

It should be placed at "Domain Services Layer", it is separate layer altogether.
Also, will add one more layer here "Application Services".

App Services talks to Domain Services layer to apply business logic and then lastly return the Model.

So,
Controller will ask Application Service for Model and the flow will go like,

    Controller->Application Services(using domain services)->Model
荒芜了季节 2024-10-16 11:22:04

MVC 模式和 Asp.net 框架对于模型应该是什么没有区别。

MS 自己的示例在模型中包含持久性类。您关于模型中的成员身份的问题。这取决于。你的模型中的类是否属于某些东西?谁登录和显示什么数据之间是否存在联系?权限系统中是否有可编辑的数据过滤部分?谁最后更新或编辑了您域中的对象部分,因为其他人需要查看它或后端支持的某些内容?

电子邮件示例也取决于情况。您是否熟悉领域事件或特别是事件?你们有单独的电子邮件发送服务吗?发送电子邮件的行为是您的域的一部分,还是您系统范围之外的应用程序级别问题? UI 是否需要知道电子邮件是否发送成功?发送失败的邮件需要重试吗?是否需要存储发送的电子邮件的内容以满足支持或客户服务要求?

这些类型的问题过于宽泛和主观,但我回答是为了让您和投票给您的每个人都能理解这一点。

您的需求/时间表/资源都会融入您的系统架构中。甚至 收入模式可以产生影响。您还必须考虑您要拍摄的模式。 DDD 与持久化模型应用程序有很大不同,两者之间的所有差异对于某些应用程序也有效。您正在拍摄测试应用程序吗?所有这些都会产生影响。

The MVC pattern and the Asp.net framework makes no distinction on what the Model should be.

MS's own examples include persistence classes in the model. Your question about membership being in the model. This depends. Are classes in your model owned by something? Is there a link between who logs in and what data is displayed? Is there filtering of data part of a permissions system that is editable? Is who last updated or edited an object part of your domain as in somebody else needs to see it or something for backend support?

The email example is also it depends. Are you familiar with domain eventing or eventing in particular? Do you have a separate service to send emails? Is the act of sending an email part of your domain or is it a application level concern outside of the scope of your system? Does the UI need to know if an email was sent successfully or not? Do emails that fail to send need retries? Does the content of the email sent need to be stored for support or customer service requirements?

These types of questions are overly broad and subjective but I'm answering so you and everybody who voted you up can understand this.

Your requirements/timelines/resources all bleed into your system's architecture. Even the revenue model can have an effect. You also have to consider the pattern you are shooting for. DDD is much different than persistence-as-model applications and all the slop in between are also valid for certain apps. Are you shooting for testing the app? All of this has an effect.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文