17

在我一直从事的一些 MVC 项目中,很明显有一些有问题的控制器已经有机地成长为上帝类——如果你愿意的话,每个半神都在自己的领域中。

这个问题可能更像是“什么去哪里”,但我认为这是一个关于 SRP(单一责任原则)、DRY(不要重复自己)和保持简洁、“敏捷”的重要问题——而且我没有足够的经验(使用这种模式和一般设计)来了解这一点。

在一个项目中,我们有一个 NutritionController。随着时间的推移,它逐渐包含了这些操作(许多都有各自的 GET、POST 和 DELETE 方法):

Index (home controller)
ViewFoodItem
AddFoodItem
EditFoodItem
DeleteFoodItem
ViewNutritionSummary
SearchFoodItem
AddToFavorites
RemoveFromFavorites
ViewFavorites

然后我们有一个 ExerciseController,它将包含许多类似的操作,例如搜索和收藏操作。是否应该将这些重构为它们自己的控制器,使其成为类似的东西?

SearchController {
    SearchExercise
    SearchNutrition
    //... etc
}

FavoritesController {
    ViewNutritionFavorites
    AddToNutritionFavorites
    AddToExerciseFavorites
    EditNutritionFavorites
    EditExerciseFavorites
    //... etc
}

在我看来,如果您将它们分解为单独的控制器,您将在某种程度上增加一个难以置信的大依赖来处理您需要的信息。或者,您将拥有一个完全通用的处理应用程序,该应用程序将非常难以处理,因为您必须跳过这么多圈才能获得所需的效果(在 M、V 或 C 级别)。

我在想这个错误的方式?例如,我是否应该有一个通用的收藏夹对象,然后让控制器决定将它扔到哪个视图?

*抱歉拼出首字母缩略词 - 我这样做是为了以防其他人遇到这个问题并且对这些东西是什么一无所知

编辑: 我执行的所有逻辑都在服务层中处理。例如,控制器会将“新”FoodItem 发送到服务。如果它已经存在,或者它有错误,该服务会将它冒泡回控制器。

4

4 回答 4

12

我会根据责任分解你的第一个清单:

家庭控制器

  • 指数

食品项目控制器

  • 查看食品项目
  • 添加食品项目
  • 编辑食物项
  • 删除食品项
  • 搜索食品

营养控制器

  • 查看营养总结

收藏夹控制器

  • 添加到收藏夹
  • 从收藏夹中删除
  • 查看收藏夹
  • 搜索收藏夹

Django的 MVC 方法是将职责分离到“应用程序”中,每个应用程序都有自己的模型、控制器,甚至在必要时使用模板。你很可能会有一个食品应用程序、一个营养应用程序、一个搜索应用程序和一个收藏夹应用程序。

编辑:OP提到搜索对每个控制器都更具体,所以我做了这些动作。然而,搜索也可能只是一个通用的全局事物,所以在这些情况下,一个 SearchController 就可以了。

于 2009-06-21T16:17:23.047 回答
2

照苏维特说的做。你想让控制器保持简单。听起来您最终在控制器中使用了太多的协调逻辑。请记住,他们负责连接视图和模型。这种协调逻辑可能应该被拆分为服务。

我有这种感觉,因为您提到您的控制器可能会产生巨大的依赖关系。好吧,如果 FavoritesController 需要了解营养和锻炼最爱(在同一视图中显示),请不要让您的控制器依赖于 2 个存储库,如类。相反,封装该协调行为。也许创建一个知道如何返回营养和运动收藏夹的收藏夹服务。该服务可能会委托给 NutritionFavoritesService 和 ExerciseFavoritesService。这样,您的控制器仅以 1 个依赖项结束,您保持事物干燥,执行 SRP,并将您的业务逻辑集中在控制器以外的某个地方。

于 2009-06-21T16:23:52.580 回答
1

我也经历过这类维护难题,并发现坚持使用类似“Rails”的方法非常有助于让我的控制器保持专注和不臃肿。

如果我发现自己添加了具有不寻常名称的操作,例如。使用博客示例 AddPostToBlog,这将是一个使用 Create 操作创建新 Post 控制器的标志。

换句话说,如果动作不是 Index、New、Create、Show、Edit、Update 和 Destroy 动作之一,那么我添加一个特定于我需要的动作的新控制器。

以你为例。

SearchController {
    SearchExercise
    SearchNutrition
    //... etc
}

我会将其重构为...

   SearchExerciseController {
           Index   
   }

   SearchNutritionController {
           Index   
   }

这可能意味着拥有更多控制器,但在我看来,这比以往扩展的“上帝”控制器更容易管理。这也意味着控制器更加自我记录。

例如。SearchExercise 操作是返回视图以搜索练习还是实际执行搜索?您可能可以通过查看参数和正文来确定这一点,但它不像新建和创建或编辑和更新操作对那样简单。

SearchController {
    SearchExercise       
}
于 2010-08-02T14:20:10.273 回答
1

我对那个框架不太熟悉,但我可以提供一些一般性的建议。控制器可能应该只知道如何完成单个动作,或者调用其他单个动作控制器来完成一系列相关动作。任何必须在动作之间传递的信息都应该以某种方式通过模型层传递,因为该信息很可能与底层模型相关。

于 2009-06-21T16:23:30.863 回答