违反单一责任原则的最佳例子是什么?

时间:2009-08-30 18:57:01

标签: single-responsibility-principle solid-principles

我正在寻找一些违反单一责任原则的代码示例。不要向我展示鲍勃叔叔的书籍或网站上的任何例子,因为这些都是在互联网上贴满的,就像这样:

interface Modem
{
    public void dial(String pno);
    public void hangup();
    public void send(char c);
    public char recv();
}

6 个答案:

答案 0 :(得分:11)

您的面向对象设计的粒度是一个品味问题,可能不适合其他人。因此,我不会在一些业务逻辑类中寻找违反单一责任原则的例子,讨论它是否有太多或太少的事情要做。

在我看来,最好的例子(最差的副作用)来自打破你的应用程序的分层。 F.ex:

  • 在数据访问层中执行业务逻辑(其唯一责任应该是提供对应用程序的持久访问)
  • 从(通过)域模型访问业务服务(其唯一责任应该是存储应用程序的大部分状态)
  • 在视图层执行复杂的业务逻辑(负责数据显示和用户输入)

答案 1 :(得分:4)

以下是我必须承担的PHP项目的一些代码:

class Session
{
    function startSession()
    {
        // send HTTP session cookies
    }

    function activateUserAccount()
    {
        // query the DB and toggle some flag in a column
    }

    function generateRandomId()
    {}

    function editAccount()
    {
        // issue some SQL UPDATE query to update an user account
    }

    function login()
    {
        // perform authentication logic
    }

    function checkAccessRights()
    {
        // read cookies, perform authorization
    }
}

我相信这堂课确实很多。

答案 2 :(得分:1)

实际上,在我使用的大多数OO语言中,顶级Object类就是一个很好的例子。例如,在Ruby中,Object类(或更确切地说是混合到Kernel中的Object mixin)有45个公共实例方法。现在,其中一些是别名,但仍然必须至少有20个,而且它们来自各地。我可以很容易地确定至少5个职责。

现在,我不是故意选择Ruby。这是我最喜欢的编程语言。这就是我用它作为例子的原因:因为它是我最熟悉的语言。我有理由相信我写的关于Ruby的内容也至少应用于Java和.NET。

答案 3 :(得分:0)

关于SRP的线索是定义责任,以便您的实现能够做到这一点。这就像你制定一个规则(通过给一个班级一个名字和一个责任),然后试图遵循它。

因此,如果您没有关注它,那么要么没有正确定义规则,要么在实现规则时不一致(或两者都有,这可能是最常见的情况)。

我通常会发现这些课程没有给出一个半合半的尝试来定义一个主要责任或好名字是最好的违规行为。然后你只需阅读全班,试着确定是否有任何明确的职责。

答案 4 :(得分:0)

确定班级的“责任”是一个定性问题。
只是看一下给定的类代码,无论如何都无法让我们了解它如何处理它的可复制性。
根据我的经验,至少需要考虑对类的需求更改将如何传播到其他模块(或者其他类的更改将如何传播到此类)。

由于@schmeedy给出了“打破系统分层”的一个很好的解释,我认为这只是分析“责任域”的方法之一。

我试图进一步讨论。我的尝试是以定量的方式定义“责任” 我博客上的一些讨论:http://design-principle-pattern.blogspot.in/2013/12/single-responsibility-principle.html

答案 5 :(得分:0)

#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>

@interface Spreadsheet : NSObject

- (void)loadFromURL:(NSURL *)url;
- (void)saveToURL:(NSURL *)url;
- (void)drawTo:(CGRect*)targetArea withContext:(CGContextRef *)context;

@end

我认为上面的例子违反了SRP。

从表面上看,很明显,班级负责一件事:电子表格。它区别于文档管理问题域中的其他实体,例如Word Processing。

但是,请考虑Spreadsheet对象可能发生变化的原因。

电子表格底层的模型可能会有变化。这会影响加载和保存代码,但不会影响电子表格的绘制方式。因此,加载/保存职责与绘图职责分开。我们班有两个职责。

因此,如果我们考虑改变课程的所有合理可预见的理由,并且看到课程中只有特定的方法会受到影响,我们就会有机会分担责任以获得更集中的课程。

修订后的课程将是:

@interface SpreadsheetEncoder

- (NSData *)encodedSpreadsheet:(Spreadsheet *)spreadsheet;
- (Spreadsheet *)spreadsheetFromEncodedData:(NSData *)data;

@end

@interface Spreadsheet2 : NSObject

- (NSData *)data;
- (instancetype)initSpreadsheetFromData:(NSData *)data;
- (void)drawTo:(CGRect*)targetArea withContext:(CGContextRef *)context;

@end

随着产品开发的进步,我们可以再次扪心自问,可以改变的是什么?然后重构这些类,让他们只负责一个问题。 SRP仅与问题域和我们在给定时间对它的理解有关。

在我看来,SRP归结为询问可以改变什么?&#39;和&#39;会受到什么影响&#39;。当什么可以改变&#39;只映射到受影响的一件事,你有一些实现SRP原则的类。