MVC的真正好处是什么?


对于那些刚开始编程或已经习惯某种程度并开始考虑设计的人来说,我认为了解MVC模型是一大难题。

这通常写在参考书和技术文章中。

"让我们在编写代码时考虑MVC模型!"

"让我们在模型中编写业务逻辑!"

"不要在View中编写逻辑!"

"让我们的目标是瘦控制器,胖模型!"

"我们为圣诞节节目!"

您认为:
"然后,让我们牢记MVC来编写……"

但是,当您到达本文时,您应该在思考:

"您可以在不了解MVC的情况下进行某些工作。为什么您必须考虑这些麻烦的事情!"

是的。您可以创建一个可以正常运行的应用程序,而无需了解MVC。

即使我查找它,"在Controller中编写业务逻辑也不好"
我只是写了那封信,而我毕竟不明白这样做的好处。

在本文中,

MVC模型的优点是什么?

我想通过实际编写代码并将其与参考示例一起介绍一个关于

的想法。
(参考示例是Ruby on Rails,所以对于那些学习其他框架的人感到抱歉...)

什么是MVC模型?

首先是什么MVC模型?
有一篇文章准确地显示了答案。

关于MVC模型

粗略地概括,源代码是Model,View,
让我们通过将应用程序划分为三个角色(称为控制器)来设计应用程序。那是。

  • 查看???用户可以看到的屏幕
  • 模型???在哪里编写业务逻辑
  • 控制器???上面,连接了模型和视图的位置

变为


如下图所示。

MVC.jpg

MVC的起源

那么为什么要建立这种MVC模型呢?
对此也有一篇很好的文章。

MVC,您真的了解吗?

总之,

  • 首先,视图,模型,控制器都试图在一个地方完成
  • 但是,对于设计人员来说,处理显示器的外观和对数据处理部件的工程师来说更容易,因此视图和模型是分开的。
  • 为了根据View的详细命令分支过程,将Controller分隔为View和Model之间的桥梁。

我认为是

MVC的好处

如上所述,将其分为三部分可以获得以下优点。

  • 它使设计人员和工程师之间的协作更加容易
  • 如果仅使用Model和View,则View的详细说明将使处理变得复杂,因此接收详细说明的Controller将是一个缓冲。

这是主要优点,但我认为还有其他好处。
这是本文的主题。

MVC的其他好处

"控制器是连接View和Model的角色,所以让我们编写Model的逻辑"
我明白那个。但是,不仅因为这个原因,我认为在Model中编写逻辑具有以下优点。

  • 将逻辑放在模型上可以更轻松地重用代码
  • 通过将验证和回调集中在模型上,可以防止意外的错误和数据重写。

让我们实际编写代码并检查它。

编写代码示例

考虑一个类似Twitter的应用程序。
假设您有一个users_table代表一个用户,一个tweets_table代表一条推文,以及一个images_table,它是一条推文的附加图像。
由于用户进行多条推文,因此它具有user : tweet = 1 : N关系。
此外,tweet具有tweet : image = 1 : N关系,因为可以附加多个图像。
请注意,为清楚起见,我们在tweets_table中创建了一个名为published的列,以创建一个标志来确定它是公共的还是私有的。

users_table具有以下结构。

<表格>

列名

说明

数据类型


<身体>

名称

用户名

字符串


tweets_table具有以下结构。

<表格>

列名

说明

数据类型


<身体>

内容

推文内容

文字

发布

公开或草稿(true:公开false:草稿)

布尔

user_id

链接的用户ID

整数


images_table具有以下结构。

<表格>

列名

说明

数据类型


<身体>

网址

图片网址

字符串

tweet_id

关联推文的ID

整数


模型的源代码如下。

user.rb

1
2
3
class User < ApplicationRecord
  has_many :tweets
end

tweet.rb

1
2
3
4
class Tweet < ApplicationRecord
  belongs_to :user
  has_many :images
end

image.rb

1
2
3
class Image < ApplicationRecord
  belongs_to :tweet
end

当前状态仅仅是一个关联。
现在,让我们从这里实际编写代码。

代码重用

现在假设您要创建一个功能,用户可以在其中发布(公开)推文。
让我们创建TweetsController并定义createアクション

tweets_controller.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
class TweetsController < ApplicationController
  def create
    # 投稿したユーザーを取得
    user = User.find(params[:user_id])
    # Tweetレコードの作成(公開するためにpublishedはtrue)
    tweet = Tweet.create(user_id: user.id, content: params[:content], published: true)

    # もし、image_urlがparamsの中に存在していたら、Imageレコードの作成
    if params[:image_url].present?
      Image.create(url: params[:image_url], tweet_id: tweet.id)
    end
  end
end

如果仅在控制器中编写所有内容,它将看起来像这样。
由此,实现了tweet发布功能。

接下来,让我们创建一个将推文保存为草稿的函数。
让我们在DraftsController中创建createアクション
实际上,您可以使用TweetsController处理它,但是为了方便起见,在这里我们将其分开。

drafts_controller.rb

1
2
3
4
5
6
7
8
9
10
class DraftsController < ApplicationController
  def create
    user = User.find(params[:user_id])
    Tweet.create(user_id: user.id, content: params[:content], published: false)

    if params[:image_url].present?
      Image.create(url: params[:image_url])
    end
  end
end

看起来像这样。
现在,您可以保存该推文的草稿。

但请稍候。它与TweetsController中的createアクション代码类似吗?
是的。唯一的区别是publishedtrue还是false

关于

,如果将它们放在一起,是否可以重复使用?
因此,让我们在Model中编写逻辑。

tweet.rb

1
2
3
4
5
6
7
8
9
10
11
12
class Tweet < ApplicationRecord
  belongs_to :user
  has_many :images

  def self.create_with_image(user, params, published)
    Tweet.create(user_id: user.id, content: params[:content], published: published)

    if image_url.present?
      Image.create(url: params[:image_url])
    end
  end
end

这非常激进,代码很脏,但是您可以这样编写。
然后,TweetsControllerDraftsController将按以下方式刷新。

drafts_controller.rb

1
2
3
4
5
6
class DraftsController < ApplicationController
  def create
    user = User.find(params[:user_id])
    Tweet.create_with_image(user, params, false)
  end
end

tweets_controller.rb

1
2
3
4
5
6
class TweetsController < ApplicationController
  def create
    user = User.find(params[:user_id])
    Tweet.create_with_image(user, params, true)
  end
end

这样,保存推文和图像的过程可以在多个控制器上重复使用。
这就是为什么在Model中编写逻辑可以使重用代码更加容易的原因。

可以防止意外错误和数据重写

接下来,让我们考虑一下用户何时进行新注册。
现在,假设您要对用户名设置唯一约束。
这时,它尝试不对Userモデル进行验证。
然后UsersController将如下所示:

users_controller.rb

1
2
3
4
5
6
7
8
9
10
class UsersController < ApplicationController
  def create
    users = User.where(name: params[:name])

    # params[:name]が他のユーザーの名前で使われているか確認して、なければ作成
    if users.blank?
      User.create(name: params[:name])
    end
  end
end

看起来像这样。
现在,您已将用户名实现为唯一。

但是,如果您想在其他地方创建用户怎么办?

1
2
3
4
5
6
users = User.where(name: params[:name])

# params[:name]が他のユーザーの名前で使われているか確認して、なければ作成
if users.blank?
  User.create(name: params[:name])
end

是否每次都要编写此代码?
在极少数情况下将其省略,则有可能它不是唯一的。

这是上图。

MVC.jpg

对此,您只能通过模型??与数据库进行交互。
换句话说,如果您在模型中进行验证,即使您忘记检查它是否唯一,也将始终对其进行验证,并且将无法保存数据。

user.rb

1
2
3
4
5
class User < ApplicationRecord
  has_many :tweets

  validates :name, uniqueness: true
end

这样可以确保您的用户名是唯一的。
这意味着您可以防止意外的错误和数据重写。

概括

我认为以上是我认为的MVC的优点。
(我不能否认Ruby on Rails仅遵循定义,但是...)
我认为还有更多优点,但我重点介绍了两个。

应用程序设计没有答案,我认为这是对还是错。
最重要的是,考虑到自身的优缺点,我认为可以设计应用程序的工程师是一流的工程师。