19

我基本上想知道有多少人认为在现实世界的代码中使用单一职责原则是合理的,以及有多少人实际这样做了。在Podcast #38中,Joel 谈到这种 OOP 原则在现实世界中是多么无用;并且这进一步证明了像鲍勃叔叔这样的人可能没有编写过非平凡的系统。

我亲自编写过一些软件项目或在一些软件项目中发挥了重要作用,但在我年轻的职业生涯中直到现在才遇到这种模式。我喜欢这个原则的声音,并且真的很想开始使用它。我发现 Joel 在播客中的论点非常薄弱(如果您继续阅读此处的博客评论,其他人也会如此)。但是,这有什么真相吗?

社区是怎么想的?

4

9 回答 9

25

我有一些应用SOLID原则的经验,我的经验主要是好的。我还听了播客,听起来 Jeff 和 Joel 都没有尝试过他们谈论的任何事情,时间足够长,无法真正评估其好处。反对的主要论据通常是“您编写更多代码”。如果我看看我所做的事情,我会多写 10% 的代码(通常是接口定义),但因为一切都是高度解耦的,所以它更易于维护。我几乎从来没有遇到过我的应用程序某个部分的更改会破坏其他部分的情况。所以我必须维护的 20% 的额外代码是为自己买单的。

Jeff 也错过了代码质量这一点。他不认为代码质量对客户有很大好处。他是对的,客户不在乎。客户确实关心快速实施新功能,这就是代码质量的用武之地。我发现,保持尽可能高的代码质量的投资总是在几个月内收回成本。高品质 = 低维护。

我同意他们的观点,就像任何事情一样,你必须对这些事情务实。如果您需要交付某些东西,那么请继续快速而肮脏地完成它。不过事后清理。

于 2009-01-28T18:24:42.480 回答
8

我正在做一个项目,该项目在一个应该可以被其他人轻松扩展的框架中做很多不同的、非常复杂的事情。

起初,班级很大,做的事情很多。为了改变这些行为,您必须扩展这些类。这些方法都是虚拟的,不会改变对象的状态,所以很容易做到这一点。

但是随着系统的发展,框架最终会变成一系列单体对象,每个对象都有很长的继承链,这一点变得越来越清楚。这也导致了意外的依赖关系——一个抽象方法采用类 X 的集合来生成在基类中定义的对象 Y,这要求每个人都必须这样做,即使它对继承树的一半没有意义。这也导致了需要数十个单元测试才能使代码覆盖率超过 80% 的大量类,而且复杂性如此之大,以至于您不确定是否正确地涵盖了所有内容。很明显,这种设计会导致框架非常僵化和不灵活。

因此,我们按照 SRP 线重新设计了所有内容。您将拥有您的接口、一个基类,并且可能还有一个或多个实现类。每一个都组成执行整个过程的关键功能的不同对象。如果你想改变一个部分,你没有重写一个方法,你会产生另一个对象来扩展必要的接口/基类并以不同的方式执行它的工作。SRP 甚至被分解为类方法的参数和返回值。对于那些需要灵活的系统部分,而不是传递用于生成 Y 对象的 X 类的集合,创建了一个类来封装 Y 对象的生成过程。然后系统中的组件将传递这些生产者,将它们与其他生产者组合(生产者的责任),并最终使用它们来生产 Y。这允许创建不同类型的生产者,所有这些都可以完全按照相同的,尽管他们做了截然不同的事情。此举还大大减少了每个类的代码库,并使它们更容易测试。

我想说的是,作为一个新开发者,将所有内容分解到这个级别是非常困难的。您几乎必须编写一大堆泥巴,了解它的工作原理,然后将其重新设计为几个不同的组件,每个组件负责整体的一部分。

于 2009-01-28T18:37:03.437 回答
4

我没有读过或听过乔尔的评论,所以不能具体评论。

我认为你必须从目标的角度来看待单一责任原则,而不是严格的要求。与软件开发中的许多事情一样,应该为理想而奋斗,但是,除非您的代码没有金钱收益或成本,否则您必须务实地满足客户的需求。

于 2009-01-28T18:12:34.580 回答
4

在实践中,在 OO 情况下很难获得真正的 SRP。考虑一个存在于复杂系统中的类。它可能只有一项面向业务的职责(例如打印报告),但它在内部还有许多其他违反纯 SRP 理念的职责,例如日志记录和异常处理。如果您显着更改您的日志记录机制,您可能需要更改您的打印类进行的调用。

这就是设计 AOP 的原因。使用它,您无需更改任何内容,只需更改日志记录类即可更改日志记录。

出于显而易见的原因,争取面向业务的 SRP 是件好事,但对于足够复杂的系统,您永远不会在 OOP 中获得真正的 SRP。AOP,当然,但不是 OOP。

我不知道这是否是乔尔的推理,但这就是我处理这个想法的方式。

于 2009-01-28T18:15:45.713 回答
4

大量编程理论中的一些最大的问题是他们专注于建议代码中的好的属性,实际上是代码的好属性。它们是正确的,因为它们本质上是正确的,因此不是特别有用。

是的,代码应该写得很好,是的,事情不应该被可怕地重复,是的,更改不应该在意想不到的地方造成奇怪的中断。但是,归根结底,以简单易懂的方式表达解决方案的真正简单、真正一致的代码远比满足某些严格原则的大型复杂系统更有价值。作为一个行业,我们倾向于把好的想法走得太远,在寻求“正确”解决方案而不是最好的解决方案时造成大量不必要的复杂性。

保罗。

于 2009-01-28T20:36:17.643 回答
1

我认为成为一名纪律严明的 OO 开发人员并尽可能遵守 SRP 的最大好处是易于测试和维护,所以我认为 SRP 对于任何要测试/维护的系统来说都是一个很好的目标(基本上,除了一次性系统)。

于 2009-01-28T18:46:36.977 回答
1

我认为 SOLID 原则有时不符合设计类时通常应用的自然/业务逻辑。Robert C. Martin 举了一个 Rectange 和 Square 类的例子(Square 不应该是 Rectangle 的后代)。

http://www.hanselminutes.com/default.aspx?showID=163

我不确定它是否与 SRP 有关,但想法是一样的。SOLID 原则可能会导致违反直觉的决定,而且很难跨越这个障碍。

对我来说,“准则”比“原则”更合适。

于 2009-02-08T03:57:43.370 回答
0

总的来说,我同意 SOLID 原则,但您也必须将它们纳入上下文。如果您正在编写概念证明,那么 SOLID 原则就不那么适用了。

另一方面,如果您要开发的产品的使用寿命将跨越数年,那么您最好仔细查看 SOLID 原则并加以应用。否则,它将在生产力方面花费公司大量资金。

关于乔尔和他的评论,他有一个有效的观点。有时产品需要发货或公司倒闭。就是那样子。

作为开发人员,交付产品是您的工作,但仅仅因为截止日期很紧并不意味着您使用糟糕的架构。选择使用数据集还是业务实体是一个简单的决定,两者都有类似的实施工作,但从长远来看,两者之间的新功能开发和维护是激烈的。

于 2009-01-28T18:23:54.620 回答
0

我认为应该可以为所有类编写一个简单的一行主要职责。这个单行中的“和”这个词通常不是一个好兆头。单一职责通常归结为选择适当的抽象。

GUI 附近的类倾向于反映 GUI,并具有“成为 XXXX 的 gui”的单一职责。懦夫的解决方案..

于 2009-01-28T18:38:20.097 回答