7

我最简单的 ASP.NET MVC 2 控制器调用我的服务层并使用 AutoMapper 将视图模型映射到实体。一切看起来都很棒,没有重复的代码。

但是,当我遇到类似行为的场景时,我很难平衡单一责任原则 (SRP) 和不要重复自己 (DRY)。这方面的一个例子可能是需要添加/编辑车辆,其中一些属性/行为是共享的,而其他属性/行为是特定车辆独有的。

如果我争取真正瘦的控制器(从而尊重单一职责原则),我最终会在视图和控制器中重复代码,但会有细微的变化(标题、字段标签、字段可见性、下拉值、选择标准等)。

如果我争取不重复的代码,我最终会将太多的逻辑捆绑到一个控制器/视图中,并且它会变得臃肿。

有哪些方法可以解决控制器/视图中的重复代码?我不是在谈论可以分解到存储库中的数据库代码。我也不是在谈论可以分解到服务层的业务逻辑。我正在寻找可以帮助我在上述场景中产生最佳解决方案的工具和/或经验法则。

4

4 回答 4

3

你得到:

  • 部分
  • 渲染动作
  • 动作过滤器
  • 服务层和助手类(不是 HtmlHelper)
  • 模型粘合剂
  • 基本控制器
  • 依赖注入

因此,您的视图可以为相似的部分调用共享的部分/操作,可以通过操作过滤器准备公共数据,可以将数据库访问代码隐藏在智能模型绑定器中,或者您可以拥有父控制器,子控制器可以通过特定的调整来覆盖。当然,还有好的旧服务层,您只需将通用代码提取到帮助程序/静态方法中,或者更好的是,注入特定的实现。

这不是什么新鲜事,老套路。

或者,也许,你的控制器做了太多的工作?这是上面的东西也有帮助的地方。ASP.NET MVC 有很好的工具来隐藏基础设施层代码并将其从控制器中移开。如果它不是基础设施 - 它可能属于域层。在那里,您可以使用继承、组合和其他 OOP 技巧。

具体例子。假设您的控制器应该以不同的方式设置一些属性。

  1. 如果主要是格式化或选择要显示的属性,您可以使用自己的视图来执行此操作
  2. 您可以让您的实体拥有虚拟方法 - 即重构代码以将决策移动到域层而不是控制器
  3. 您可以拥有辅助 ViewDetails 类,它们将获取您的实体并根据您的需要获取数据;这是一个肮脏的把戏,但有时很有用;您将决定委托给另一个“策略”类
  4. 您可以使用操作过滤器将此数据添加到 ViewData,或调整特定的 ViewData.Model 类型(查找它的一些接口)。
  5. 您可以拥有抽象控制器,其中子级将实现细节传递给基本构造函数,例如 (): base(repository => repository.GetSpecificData())

等等。我实际上在适当的地方使用它们。

于 2010-11-12T20:47:02.870 回答
0

您太担心 SRP 和 DRY。它们只是原则,并不总是正确的。如果 SRP 和 DRY 使您的代码更易于维护,那么它们是很好的,但如果它们妨碍了它们,那么请忽略它们。MVC 类似。它在简单的小型桌面应用程序中很有用,但不适用于 Web 应用程序。Web Forms 对于互联网世界来说要好得多,而 MVC 是 1980 年代的东西。

于 2010-11-16T03:22:39.453 回答
0

在这些情况下,我建议您使用 SRP 而不是 DRY。我在这里写了一个详细的答案。

简而言之,两者都是有助于保持代码可维护性的规则。DRY 是一种低抽象级别的机制,而 SRP 是一种高抽象级别的机制。通过维护应用程序,高抽象级别的结构比低抽象级别更重要。

在您的情况下,我认为没有必要放弃 DRY。

这方面的一个例子可能是需要添加/编辑车辆,其中一些属性/行为是共享的,而其他属性/行为是特定车辆独有的。

在这种情况下,许多设计模式都可以提供帮助。您可以使用装饰器、合成器等...结合不同类型车辆的构建器。

于 2014-05-25T03:13:23.713 回答
0

我发现ApiEndpoints对此非常有用。您为每个控制器方法创建一个类。多一点代码,但我认为它很干净。

于 2021-04-14T04:41:32.587 回答