问题标签 [single-responsibility-principle]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
4 回答
1628 浏览

asp.net-mvc - ASP.NET MVC - 当 SRP 和 DRY 出现冲突时

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

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

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

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

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

0 投票
2 回答
398 浏览

asp.net-mvc - MVC 中的多个视图与一个“复杂”视图

这是在我们的一次回顾中提出的,需要一些额外的反馈和抽查。我们目前有许多基于布尔标志启用/禁用的视图(Model.IsNew 就是一个例子)。我认为视图应该尽可能简单,控制器应该确定该视图的数据,而不一定是它的工作方式。我认为视图,部分或全部,应该 - 告诉 - 做什么和处理它,而不是视图确定应该显示/隐藏什么。一个非常基本的示例如下,但涵盖了这两个方面,主要反映了我们所拥有的......

控制器有一对称为详细信息的方法(post/get)。[Get]Details 有一个参数,Id 和 [Post]Details 需要 id 和一个视图模型。在帖子中,该方法大约有 30 行长,检查有效模型,确定其是否新,某个值是否更改(触发重定向)等等(我认为这是不正确的)。[Get]Details 检查空 id,填充必要的下拉列表,没什么特别的(我认为这是正确的)。详细视图本身包含一些逻辑: If (!Model.IsNew) { RenderAction(History => History.Show(id); } (我认为 if 中的这个是不正确的, Show 应该知道要显示什么,不管它是否是新的)。对此的加号是所述详细视图的布局没有完成两次。详细信息/添加几乎相同,

想法、意见、见解?

0 投票
1 回答
86 浏览

security - 我的安全逻辑应该去哪里?

假设我有一个调用存储库层的 ASP.NET MVC Web 应用程序,该存储库层构建在 nHibernate 之上。控制器传递一个ISecurityToken封装当前用户身份和权限的存储库,存储库在查询时使用它只返回用户应该能够看到的行。

我希望实体(票证)只能由特定的用户组以及票证分配给的用户关闭。换句话说,假设CanCloseTicket()方法需要两个输入:

  1. 票证本身(或其当前所有者 ID)
  2. 当前用户的ISecurityToken

这种假设的方法应该在哪里?我可以看到几种可能性,但每种都有其缺点。

  • 在控制器中:控制器可以访问所有必要的东西,但这使得安全性被绕过成为可能。(“糟糕,在设置为 false 之前,我忘记在此操作中调用 CanCloseTicket() ticket.IsOpen!”这闻起来很糟糕。
  • 在存储库中:存储库也可以访问这两个部分,但我还必须将Ticket.IsClosed's setter 设为私有以阻止上述相同事情的发生。存储库位于与模型完全不同的程序集中,因此使用内部设置器将不起作用。相反,我可以将 setter 公开并将属性的当前值与其原始值进行比较,如果非特权用户将其关闭,则返回错误,但这对我来说也有点奇怪。(“糟糕,我忘记检查repo.CloseTicket()这个动作方法的返回值了!”)
  • 在票证中:添加Ticket.Close(ISecurityToken token)并让实体负责自己的安全逻辑感觉就像违反了SRP

我认为存储库是这里最好的选择,但感觉更像是最差的选择。还有别的事吗?

0 投票
1 回答
293 浏览

c# - SRP:为什么使用实例字段值而不是参数?

0 投票
1 回答
358 浏览

php - 在 MVC 中缓存图像的设计模式?

我正在设计一个将在 MVC CMS 中使用的图像缓存系统。图像缓存器的主要目的是修改图像:缩放、裁剪等并将它们缓存在客户端站点中。

我创建了一个与数据库交互的图像缓存模型和映射器,以跟踪图像并了解对它们应用了哪些类型的操作(缩放、裁剪等)。

除了模型和映射器之外,我还创建了一个 ImageCacher 类,API 使用它来管理基于客户端站点传递的参数的模型和图像创建,该类创建图像并生成视图的图像链接.

一位同事认为我需要在模型中包含最后一个类的功能,因为大部分逻辑应该在模型中。

我很不同意他的观点,因为我觉得模型的职责是处理有关在数据库级别缓存的图像的信息,而 ImageCacher 类的职责是创建我们将缓存的 url/图像(保持单一职责原则)。除此之外,我认为模型不应具有与演示相关的功能,例如创建或显示图像。

有人对此有任何见解吗?是否有一种特定的设计模式可以使这种任务划分清晰并且图像缓存器可重用?我应该在模型中添加所有逻辑吗?

谢谢你。

0 投票
1 回答
471 浏览

c# - 如何将 SRP 应用于用户界面类?

我的应用程序使用 DI 框架,并在必要时遵循“程序到接口”实践。

我使用构造函数注入,因为我想明确地查看依赖关系。但是现在我的表单类的构造函数接受了太多参数(例如> = 4)。

问题:由于 UI 设计通常不遵循 SRP,因此 Winform 类可能具有n构造函数依赖项。你喜欢让它们保持原样,而是传递一个代理对象,使用服务定位器......?考虑到没有使用 aop 框架,您是否还在每个构造函数中注入“方面”(记录器等)?

0 投票
1 回答
140 浏览

oop - 转换数据时如何避免违反 SRP

在编写应将数据从格式 A 转换为格式 B 的类时,如何避免违反“单一责任原则”?此类更改有两个原因,因为格式 A 和 B 的规范都可以更改。

0 投票
1 回答
161 浏览

asp.net - ASP.NET WebForms - 控件设计(wrt 数据)

我正在使用 WebForms 设计/构建一个中等规模的 ASP.NET Web 应用程序。该项目的主要工作是构建每个 Web 表单,我不知道如何设计(在代码/数据/数据流意义上)我的控件。

我会给你一些我正在处理的例子,这样你就可以理解我的意思:


应用程序中的一项常见任务是输入和显示街道地址。因此,我创建了一个名为“AddressFields”的用户控件,其中包含一系列 HtmlInputText 元素(一个用于第 1 行,另一个用于城镇/城市、国家/地区、邮政编码等)。我的数据库实体类包含一个名为“地址”的类,因此该控件具有以下方法:

  • void ShowAddress(Address addr) - 用适当的文本填充 HtmlInputText 元素)。
  • void UpdateAddress(Address addr) - 使用 HtmlInputText 元素的当前内容更新 addr 的内容
  • Address CreateAddress() - 创建一个新的 Address 实例,然后将其传递给 UpdateAddress,然后返回它

到目前为止,一切都很好。这是有效的,因为 AddressFields 控件是“愚蠢的”,它所做的只是向用户显示和检索数据。ViewState 也直接由 HtmlInputText 字段管理,因此不需要额外的逻辑。


我的应用程序中的另一个实体是“客户端”,它是一个具有地址属性的类,但这个类也有一些更复杂的方面。例如,客户有一系列可以分配的标签(我的应用程序中的“类别”)。在本例中,我设计了 ASP.NET CheckboxList 控件的子类。

我创建了另一个名为“ClientFields”的 UserControl,其中包含显示客户端信息的所有必要字段(包括 AddressFields 控件),但它还包括名为“CategoryList”的 CheckboxList 子类。

这里的问题是需要将 CategoryList 控件提供给要显示的数据(但不是在回发时,因为它使用视图状态)。在这种情况下,我的问题是:谁负责连接数据库并检索类别列表

它是 CategoryList 控件吗?(如果是这样,它在控件生命周期中的哪个位置查询数据库?它不能在 Control.Load 中执行,因为它发生在 ClientFields 被填充之后。它发生在 ClientFields 本身中吗?(再次,然后在生命周期中的哪个位置是否会发生这种情况,因为 ClientFields 在 Page.Load 中调用了 ShowClient(Client c) 方法。另一种方法是从 ClientFields 中公开 CategoryList,以便页面可以直接访问它,但这违反了良好的软件设计。

0 投票
5 回答
889 浏览

solid-principles - 编写只做一件事并做好的程序

我可以通过封装、依赖注入最少知识原则你不需要它来掌握“做一件事”的部分;但是我如何理解第二部分“做好”?

给出的一个例子是完整性的概念,在同一篇 YAGNI 文章中给出:

例如,在允许添加项目、删除项目或修改项目的功能中,完整性也可用于推荐“重命名项目”。

但是,我发现这样的推理很容易被滥用到功能蠕变中,从而违反了“做一件事”部分。

那么,什么是查看某个功能属于“做得好”类别(因此,将其包含到函数/类/程序中)或其他“做一件事”类别(因此,排除它)的试金石?

第一部分“做一件事”最好通过 UNIX 的ls命令来理解,作为一个反例,因为它包含过多的标志来格式化其输出,这些标志应该完全委托给另一个外部程序。但是我没有一个很好的例子来看到第二部分“做得好”。

什么是一个很好的例子,删除任何进一步的功能会使其“做得不好”?

0 投票
1 回答
209 浏览

security - 在 Ubuntu 10.04 中编译 srp-2.1.2 时出错

我从http://srp.stanford.edu/source/srp-2.1.2.tar.gz下载了 srp-2.1.2 源代码。

类型:./configure ---> 一切正常

类型:制作

在这一点上,我在链接过程中不断收到同样的错误。请参阅下面的最后几行:

它找不到对“tgetent”的任何引用。我不知道那是什么意思。谁能帮我 ?

谢谢