【问题标题】:ASP.NET MVC - when SRP and DRY appear to conflictASP.NET MVC - 当 SRP 和 DRY 出现冲突时
【发布时间】:2010-11-12 18:15:05
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 太抽象了,请具体代码示例。
  • @Darin:你说得非常正确,因为我想到了我的问题——这需要一些时间,但我会看看我是否可以用更具体的东西来改进这个问题。

标签: asp.net-mvc controller dry single-responsibility-principle


【解决方案1】:

你得到:

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

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

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

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

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

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

等等。我实际上在适当的地方使用了所有这些。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 这是错误的。 MVC 对 Web 应用程序的效果甚至比对桌面应用程序的效果更好,而且对于小型应用程序来说它通常是矫枉过正的。 SRP 和 DRY 是原则,而不是设计模式之类的建议。他们总是正确的。但是,您使用的语言可能需要您重复自己,并且与您相关的开发计划可能没有给您足够的时间来提出适当的 SRP 设计。通常,时间和金钱会胜过工程。
    【解决方案3】:

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

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

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

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

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

    【讨论】:

      【解决方案4】:

      我发现ApiEndpoints 非常适合这个。您为每个控制器方法创建一个类。代码多一点,不过我觉得很干净。

      【讨论】:

        猜你喜欢
        • 2023-01-31
        • 2016-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多