ASP.NET MVC - 当 SRP 和 DRY 出现冲突时
我最简单的 ASP.NET MVC 2 控制器调用我的服务层,并使用 AutoMapper 将视图模型映射到实体。一切看起来都很棒,而且没有重复的代码。
然而,当我遇到类似行为的场景时,我很难平衡单一职责原则 (SRP) 和不要重复自己 (DRY)。例如,需要添加/编辑车辆,其中某些属性/行为是共享的,而其他属性/行为是特定车辆所独有的。
如果我努力实现真正的瘦控制器(从而遵守单一职责原则),我最终会在视图和控制器中重复代码,并有细微的变化(标题、字段标签、字段可见性、下拉值、选择标准等)。
如果我努力实现不重复的代码,我最终会将太多的逻辑捆绑到单个控制器/视图中,并且它会变得臃肿。
解决控制器/视图中重复代码的方法有哪些?我不是在谈论可以分解到存储库中的数据库代码。我也不是在谈论可以分解到服务层的业务逻辑。我正在寻找能够帮助我在上述场景中制定最佳解决方案的工具和/或经验规则。
My simplest ASP.NET MVC 2 controllers make calls to my service layer and map view models to entities using AutoMapper. Everything looks fantastic and there is no repeated code.
However, when I get into scenarios where I have similar behavior I have trouble balancing Single Responsibility Principle (SRP) with Don't Repeat Yourself (DRY). An example of this might be the need to add/edit vehicles where some properties/behaviors are shared while others are unique to a specific vehicle.
If I strive for really thin controllers (thus honoring Single Responsibility Principle), I end up having repeated code in both the views and controllers with minor variations (title, field labels, field visibility, dropdown values, selection criteria, etc.).
If I strive for non-repeated code I end up bundling too much logic into a single controller/view and it gets bloated.
What are some ways of addressing repeated code in controllers / views? I'm not talking about database code that can be factored out to a repository. Nor am I talking about business logic that can be factored out to a service layer. I'm looking for tools and/or rules of thumb that will help me produce the best solution in the scenario described above.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您将获得:
因此您的视图可以调用类似部分的共享部分/操作,操作过滤器可以准备公共数据,可以隐藏数据库访问代码在智能模型绑定器中,或者您可以拥有子控制器通过特定调整覆盖的父控制器。当然,还有很好的旧服务层,您只需将通用代码提取到帮助器/静态方法中,或者更好的是注入特定的实现。
这不是什么新鲜事,都是老套路。
或者,也许您的控制器做了太多工作?这就是上面的内容也有帮助的地方。 ASP.NET MVC 有非常好的工具来隐藏基础结构层代码并将其移离控制器。如果它不是基础设施 - 它可能属于域层。在那里您可以使用继承、组合和其他 OOP 技巧。
具体例子。假设您的控制器应该以不同的方式设置一些属性。
等等。实际上我在适当的地方使用了它们。
You get:
So your views can invoke shared partials/actions for similar parts, common data can be prepared by action filters, database access code can be hidden in smart model binder, or you can have parent controller that child controllers override with specific tweaks. And, of course, good old service layeres, where you just extract common code into helper/static methods, or, better, inject specific implementations.
That's nothing new, same old tricks.
Or, maybe, your controllers do too much works? This is where stuff above also helps. ASP.NET MVC has very good tools to hide infrastructure-layer code and move it away from controllers. And if it's not infrastructure - it probably belongs to domain layer. There you can use inheritance, composition and other OOP tricks.
Specific example. Suppose your controllers should set few properties in a different way.
And so on. I actually use all of them in appropriate places.
您过于担心 SRP 和 DRY。它们只是原则,并不总是正确的。如果 SRP 和 DRY 使您的代码更易于维护,那么它们就很好,但如果它们妨碍了,请忽略它们。 MVC 类似。它在简单的小型桌面应用程序中很有用,但不适用于 Web 应用程序。 Web Forms 对于互联网世界来说要好得多,而 MVC 则是 20 世纪 80 年代的东西。
You are worrying too much about SRP and DRY. They are principles only and are not always right. SRP and DRY are good if they make your code more maintainable, but if they are in the way then ignore them. MVC is similar. It is useful in simple small desktop applications but is not appropriate for web applications. Web Forms is much better for the internet world while MVC is something from the 1980s.
在这些情况下,我建议您使用 SRP 而不是 DRY。我这里写了一个详细的答案。
简而言之,这两条规则都有助于保持代码的可维护性。 DRY是低抽象级别的机制,而SRP是高抽象级别的机制。通过维护应用程序,高抽象级别结构比低抽象级别更重要。
对于你的情况,我认为没有必要放弃 DRY。
许多设计模式可以在这种情况下提供帮助。您可以将装饰器、合成器等与不同类型车辆的构建器结合使用。
I recommend you to use SRP over DRY in those cases. I wrote here a detailed answer.
In short both are rules which help to keep your code maintainable. DRY is a low abstraction level mechanism, while SRP is a high abstraction level. By maintain an application the high abstraction level structure is more important than the low abstraction level.
In your case I don't think it is necessary to give up DRY.
Many design patterns can help in this case. You can use decorator, composition, and so on... combined with builders for the different types of vehicles.
我发现 ApiEndpoints 对此非常有用。您为每个控制器方法创建一个类。代码有点多,但我认为它非常干净。
I found that ApiEndpoints is very good for this. You create a class for each controller method. A little more code, but I think it's very clean.