我正在寻找一些违反单一职责原则的代码的好例子。不要给我看鲍勃叔叔的书或网站中的任何例子,因为这些例子遍布互联网,就像这个:
interface Modem
{
public void dial(String pno);
public void hangup();
public void send(char c);
public char recv();
}
我正在寻找一些违反单一职责原则的代码的好例子。不要给我看鲍勃叔叔的书或网站中的任何例子,因为这些例子遍布互联网,就像这个:
interface Modem
{
public void dial(String pno);
public void hangup();
public void send(char c);
public char recv();
}
OO 设计的粒度是个人喜好问题,可能不适合其他人。因此,我不会在某些业务逻辑类中寻找打破单一责任原则的例子,讨论它是否有太多或太少的事情要做。
在我看来,最好的例子(副作用最严重)来自于打破应用程序的分层。例如:
这是我不得不承担的 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
}
}
我相信这门课确实很棒。
实际上,在我使用过的大多数 OO 语言中,顶级Object
类就是一个很好的例子。例如,在 Ruby 中,Object
类(或更准确地说是混入 的Kernel
mixin Object
)有 45 个公共实例方法。现在,其中一些是化名,但至少还有 20 个,而且他们来自世界各地。我可以很容易地确定至少 5 个职责。
现在,我并不是要选择 Ruby。它是我最喜欢的编程语言。这就是我用它作为例子的原因:因为它是我最熟悉的语言。而且我有理由相信,我写的关于 Ruby 的内容至少也 100% 适用于 Java 和 .NET。
关于 SRP 的线索是定义职责,以便您的实现只做那件事。这就像您正在制定规则(通过为类指定名称和责任)然后尝试遵循它。
因此,如果您不遵守它,您要么没有正确定义规则,要么在实施规则时不一致(或两者兼而有之,这实际上可能是最常见的情况)。
我通常发现那些在定义单一主要职责或良好名称方面没有给予半体面尝试的类是最好的违规行为。然后你只需要阅读整个课程来尝试确定是否有任何明确定义的职责。
确定一个类的“职责”是一个定性问题。
仅仅看一个给定的类代码,无论如何都不能让我们知道它处理它的责任有多好。
至少根据我的经验,非常有必要考虑对类的需求更改将如何传播到其他模块(或者其他类的更改将如何传播到此类)。
正如@schmeedy 对“打破系统分层”给出了很好的解释,我认为这只是分析“责任域”的方法之一。
我试图进一步讨论。我的尝试是以定量的方式定义“责任”。
我博客上的一些讨论:http: //design-principle-pattern.blogspot.in/2013/12/single-responsibility-principle.html
#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。
从表面上看,很明显该类负责一件事:电子表格。它区别于文档管理问题域中的其他实体,例如文字处理。
但是,请考虑电子表格对象可能更改的原因。
电子表格的基础模型可能会发生变化。这会影响加载和保存代码,但不会影响电子表格的绘制方式。因此加载/保存职责与绘图职责是分开的。我们的班级有两个职责。
因此,如果我们考虑更改类的所有合理可预见的原因,并看到只有类上的特定方法会受到影响,我们就会看到一个机会来分解责任以获得更集中的类。
修改后的课程将是:
@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 归结为问“什么可以改变?” 和“会受到什么影响”。当“什么可以改变”只映射到一件受影响的事情上时,你就有了实现 SRP 原则的类。