问题标签 [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 投票
1 回答
1867 浏览

inversion-of-control - 控制反转、带 SRP 的依赖注入和延迟加载

我和一位开发人员正在就对象属性的延迟加载进行交谈(轻描淡写)。

  • 他说使用静态 IoC 查找调用来解析和延迟加载对象的对象。
  • 我说这违反了 SRP,并使用拥有的服务来解决该对象。

那么,您将如何处理 IoC 和 SRP 之后的延迟加载?

您不能对延迟加载的属性进行单元测试。他反驳了这一说法,“你已经对 UserStatsService 进行了单元测试——你的代码覆盖了。” 一个有效的观点,但该属性仍未经过“完整”覆盖的测试。

设置/代码模式:

  • 项目正在使用严格的依赖注入规则(注入到所有服务、存储库等的 ctors 中)。
  • 项目通过 Castle 使用 IoC(但可以是任何东西,比如 Unity)。

下面是一个例子。

上面显示了延迟加载对象的示例。我说不要使用它,并在需要该对象的任何地方从 UI 层访问 UserStatsService。

编辑:下面的一个答案让我想起了 NHibernate 延迟加载的技巧,即虚拟化您的属性,允许 NHibernate 创建延迟加载本身的过载。Slick,是的,但我们没有使用 NHibernate。

没有人真正解决延迟加载的问题。一些好的文章和 SO 问题接近了:

我确实看到了延迟加载的好处。不要误会,我所做的只是延迟加载我的复杂类型及其子类型,直到我切换到忍者的 DI 方式。好处在于 UI 层,其中显示了用户的统计信息,例如,在 100 行的列表中。但是对于 DI,现在您必须引用几行代码来获取该用户统计信息(不违反 SRP 并且不违反 Demeter 定律),并且它必须走这条长长的查找路径 100 多次。

是的,添加缓存并确保将 UserStatsService 编码为用作单例模式会大大降低性能成本。

但我想知道是否还有其他人有一个 [固执的] 开发人员,他们不会完全遵守 IoC 和 DI 规则,并且有有效的性能/编码点来证明变通方法的合理性。

0 投票
2 回答
473 浏览

c# - 遵循单一职责原则设计数据库交互

我正在尝试更好地遵守单一职责原则,并且在掌握如何构建通用类设计以与数据库进行通信时遇到问题。在简化版本中,我基本上有一个数据库,其中包含:

制造商 <== 探针 <==> 探针设置

探头有制造商。一个探头有一组设置。相关对象在整个应用程序中都可以访问,坦率地说,当前的实现是一团糟。

目前,这里是如何实现通信和对象的一般视图:

我在这里看到很多问题。

  1. Database做得太多了。
  2. 这些对象在真正读取时可能是不可变的,唯一的问题是在插入之后,我不确定它们被分配了什么 ID,并且插入的对象现在已经过时了。
  3. 每当一个类需要从 中获取信息时Database,我都必须添加另一个 Get 方法来处理特定查询。

我真的不知道正确的实现是什么。我唯一真正的改进想法是某种数据库对象的基本接口,尽管它可能只有助于插入......

什么是实际实现这一点的好方法?

0 投票
1 回答
422 浏览

agile - 帮助理解单一职责原则

我试图了解责任实际上是什么,所以我想举一个我目前正在做的事情的例子。我有一个将产品信息从一个系统导入到另一个系统的应用程序。应用程序的用户可以为一个系统中的哪些产品字段选择要在另一个系统中使用的各种设置。

所以我有一个类,比如说 ProductImporter,它的职责是导入产品。这个类很大,可能太大了。

此类中的方法很复杂,例如 getDescription。这种方法不是简单地从其他系统中获取描述,而是根据用户设置的各种设置来设置产品描述。如果我要添加一个设置和一种获取描述的新方法,这个类可能会改变。

那么,这是两个责任吗?是否有一种进口产品和一种获得描述。看起来是这样,几乎我拥有的每个方法都在它自己的类中,这似乎有点矫枉过正。

我真的需要很好地描述这个原理,因为我很难完全理解。我不想要不必要的复杂性。

0 投票
4 回答
644 浏览

oop - 让一个方法做不止一件事是否违反了单一职责原则?

出于我的目的,我需要在 xml 文件中搜索特定节点,如果找到,则将其删除。我应该将搜索功能提取到它自己的方法中并将功能删除到它自己的方法中吗?这样做似乎更昂贵,因为我将搜索 xml 文件一次以查看它是否存在并再次搜索以将其删除。如果我将这两个功能组合成一个方法,我可以在找到它时立即删除它。我在这里正确理解 SRP 吗?

0 投票
6 回答
1885 浏览

oop - 在使用单一职责原则时,您如何确定“职责”的粗粒度或细粒度?

在 SRP 中,“责任”通常被描述为“改变的理由”,因此每个类(或对象?)应该只有一个理由,有人应该去那里改变它。

但是如果你把它带到极端的细粒度上,你可以说一个对象将两个数字加在一起是一种责任,也是改变的可能原因。因此对象不应该包含其他逻辑,因为它会产生另一个变化的原因。

我很好奇是否有人有任何“范围界定”策略,单一责任原则稍微不那么客观?

0 投票
1 回答
240 浏览

dependency-injection - 图表限制 - 我应该使用装饰器吗?

我有一个功能性 AdjacencyListGraph 类,它遵循定义的接口 GraphStructure。为了对此进行分层限制(例如,非循环、非空、唯一顶点数据等),我可以看到两条可能的路线,每条路线都使用 GraphStructure 接口:

  1. 创建具有一组指定各种可能限制的位标志的单个类(“ControlledGraph”)。处理此类中的所有限制。如果新的限制要求变得明显,请更新类。

  2. 使用装饰器模式(本质上是 DI)为客户端类可能希望使用的每个单独的限制创建一个单独的类实现。这样做的好处是我们坚持单一职责原则。

我会倾向于后者,但天哪!,我讨厌装饰器模式。它是混乱的缩影,IMO。老实说,这一切都取决于在最坏的情况下可能应用多少装饰器——到目前为止,我的数量是 7(我在这个阶段认识到的离散限制的数量)。装饰器的另一个问题是我将不得不在每个...单个...装饰器类中进行接口方法包装。呸。

如果有的话,你会选择哪一个?或者,如果您可以提出一些更优雅的解决方案,那将是受欢迎的。

编辑:在我看来,将建议的 ControlledGraph 类与策略模式一起使用可能会有所帮助......某种模板方法/仿函数设置,各个位在各种图形规范接口方法中应用单独的控件。还是我失去了情节?

0 投票
2 回答
662 浏览

ubuntu-9.10 - ubuntu下编译srp-2.1.2

我已经下载了 srp-2.1.2 包并尝试在 ubuntu 下编译它。但它不会被完全编译。请告诉我如何在 ubuntu 下编译它。

错误-

root@ubuntu:~/Desktop/srp-2.1.2/libsrp# make

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_client.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_conf.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_conv.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_getpass.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_sha.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_math.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_misc.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_pw.c t_pw.c:在函数“t_changepw”中:

t_pw.c:468:警告:忽略“链接”的返回值,用属性 warn_unused_result 声明

t_pw.c:470:警告:忽略“链接”的返回值,用属性 warn_unused_result 声明

t_pw.c:在函数“t_deletepw”中:

t_pw.c:540:警告:忽略“链接”的返回值,用属性 warn_unused_result 声明

t_pw.c:542:警告:忽略“链接”的返回值,用属性 warn_unused_result 声明

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_read.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_server.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c t_truerand.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c cstr.c

cstr.c:24:警告:从不兼容的指针类型初始化

cstr.c:24:警告:从不兼容的指针类型初始化

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c srp.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c rfc2945_client.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c rfc2945_server.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c srp6_client.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c srp6_server.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c yp_misc.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c yp_tpasswd.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c yp_tconf.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c nsw_tpasswd.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c nsw_tconf.c

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c nsswitch.c

rm -f libsrp.a

ar cru libsrp.a t_client.o t_conf.o t_conv.o t_getpass.o t_sha.o t_math.o t_misc.o t_pw.o

t_read.o t_server.o t_truerand.o cstr.o srp.o rfc2945_client.o rfc2945_server.o

srp6_client.o srp6_server.o yp_misc.o yp_tpasswd.o yp_tconf.o nsw_tpasswd.o nsw_tconf.o

nsswitch.o

ranlib libsrp.a

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c tconf.c

tconf.c:在函数'main'中:

tconf.c:188:警告:忽略“fgets”的返回值,用属性 warn_unused_result 声明

tconf.c:202:警告:忽略“fgets”的返回值,用属性 warn_unused_result 声明

tconf.c:230:警告:忽略“fgets”的返回值,用属性 warn_unused_result 声明

tconf.c:263:警告:忽略“fgets”的返回值,用属性 warn_unused_result 声明

gcc -fPIC -O -o tconf tconf.o libsrp.a -lcrypto -ldl -lnsl

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c clitest.c

clitest.c:在函数'main'中:

clitest.c:51:警告:忽略“gets”的返回值,用属性 warn_unused_result 声明

clitest.c:53:警告:忽略“gets”的返回值,用属性 warn_unused_result 声明

clitest.c:57:警告:忽略“gets”的返回值,用属性 warn_unused_result 声明

clitest.c:61:警告:忽略'gets'的返回值,用属性warn_unused_result声明 clitest.c:74:警告:忽略'gets'的返回值,用属性warn_unused_result声明

clitest.c:79:警告:忽略'gets'的返回值,用属性warn_unused_result声明

gcc -fPIC -O -o clitest clitest.o libsrp.a -lcrypto -ldl -lnsl clitest.o:在函数“main”中:

clitest.c:(.text+0x56): 警告:“gets”函数很危险,不应使用。

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c srvtest.c

srvtest.c:在函数'main'中:

srvtest.c:77:警告:忽略“gets”的返回值,用属性 warn_unused_result 声明

srvtest.c:103:警告:忽略“gets”的返回值,用属性 warn_unused_result 声明

srvtest.c:109:警告:忽略'gets'的返回值,用属性warn_unused_result声明 srvtest.c:118:警告:忽略'gets'的返回值,用属性warn_unused_result声明

gcc -fPIC -O -o srvtest srvtest.o libsrp.a -lcrypto -ldl -lnsl

srvtest.o:在函数“main”中:

srvtest.c:(.text+0x15a): 警告:“gets”函数很危险,不应使用。

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c getpwtest.c

gcc -fPIC -O -o getpwtest getpwtest.o libsrp.a -lcrypto -ldl -lnsl

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c srptest.c

gcc -fPIC -O -o srptest srptest.o libsrp.a -lcrypto -ldl -lnsl

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c srpbench.c

gcc -fPIC -O -o srpbench srpbench.o libsrp.a -lcrypto -ldl -lnsl

gcc -DHAVE_CONFIG_H -I。-我。-我。-fPIC -O -c srp6bench.c

srp6bench.c:在函数“do_srp6preparam”中:

srp6bench.c:197:警告:内置函数'exit'的隐式声明不兼容</p>

srp6bench.c:在函数“用法”中:

srp6bench.c:214:警告:内置函数'exit'的隐式声明不兼容</p>

srp6bench.c:在函数'main'中:

srp6bench.c:246:警告:内置函数'exit'的隐式声明不兼容</p>

gcc -fPIC -O -o srp6bench srp6bench.o libsrp.a -lcrypto -ldl -lnsl `

    -


请尽快告诉我问题出在哪里

谢谢

嗨,robsn,感谢您的回答。

好的,在使用 make 编译 libsrp 后,它将创建 libsrp.a。请告诉我,我可以将此 libsrp.a 用作共享库吗?如何使用?我想通过使用 dllimport 在 ubuntu 下的 ac# 文件中使用 libsrp。`

0 投票
1 回答
253 浏览

c# - ubuntu下的共享库

我在 ubuntu 下使用 make 编译了 srp-2.1.2,它创建了一个文件 libsrp.a。谁能告诉我如何使用 libsrp.a 作为共享库?我想通过使用 dllimport 在 ubuntu 下的 ac# 文件中使用 libsrp。请告诉我 libsrp.a 文件的含义。

谢谢

好的,当我使用 nm -D libsrp.a 然后我有

c2@ubuntu:~/Desktop/srp-2.1.2/libsrp$ nm -D libsrp.a

t_client.o:nm:t_client.o:无符号

请告诉我如何获得所有符号。

谢谢

0 投票
3 回答
2819 浏览

oop - 如何将单一职责原则应用于服务类

假设我们正在设计一个执行 CRUD(创建、读取、更新和删除)操作的 UserServiceImpl 类。在我看来,创建、读取、更新和删除是更改类的四个原因。这个类是否违反了单一职责原则?如果它违反了,那么我们应该有四个类,如CreateUserServiceImplReadUserServiceImplUpdateUserServiceImplDeleteUserServiceImpl。有很多课程不是矫枉过正吗?

假设我为创建、读取、更新和删除操作分别定义了 4 个接口,并且我的服务类实现了所有四个接口。现在我只能有一个实现类,但通过分离它们的接口,就应用程序的其余部分而言,我已经解耦了这些概念。这是正确的方法还是您发现其中存在一些问题?

0 投票
2 回答
1280 浏览

model-view-controller - MVC 中对控制器的传统使用会导致违反单一职责原则吗?

维基百科这样描述单一职责原则

单一职责原则指出每个对象都应该有单一职责,并且该职责应该完全由类封装。它的所有服务都应与该责任密切相关。

MVC 中对控制器的传统使用似乎导致程序员违反了这一原则。拿一个简单的留言簿控制器并查看。控制器可能有两种方法/动作:1) Index() 和 2) Submit()。Index() 显示表单。Submit() 处理它。这两种方法是否代表两种不同的职责?如果是这样,单一职责如何发挥作用?