我正在寻找一些违反单一职责原则的代码。不要告诉我从鲍勃叔叔的书籍或网站的任何实例,因为这些都贴满所有在互联网上,像这样的:您违反单一责任原则的最佳范例是什么?
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();
}
您的面向对象设计的粒度是一个味道的问题,可能不适合其他人。因此,我不会寻找在某些商业逻辑课中打破单一责任原则的例子,讨论它是否有太多或者太少。
在我看来,最好的例子(最坏的副作用)来自打破你的应用程序分层。 F.ex:数据访问层(其唯一的责任,应提供持续访问应用程序)
有关SRP的线索是定义责任,这样您的实施做就是那件事。这就像你制定一个规则(通过给一个班级一个名字和一个责任),然后试图遵循它。
因此,如果您没有关注它,那么您的或者没有正确定义规则,或者在实现规则时不一致(或者两者都可能是最常见的情况)。
我通常会发现那些没有给出一半体面的尝试定义一个主要责任或好名字的类是最好的违规行为。然后,你只需要阅读整个班级,试图确定是否有明确的职责。
下面是一个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
}
}
我相信这个类waaay确实不怎么样。
其实,在我所用,顶级乐最OO语言vel Object
类就是一个很好的例子。例如,在Ruby中,Object
类(或更确切地说是Kernel
mixin,混入Object
)有45个公共实例方法。现在,其中一些是别名,但仍然至少有20个,而且它们来自全国各地。我可以轻松识别至少5项责任。
现在,我不打算选择Ruby。这是我最喜欢的编程语言。这就是为什么我用它作为例子:因为这是我最熟悉的语言。我相当肯定,我写的关于Ruby的内容至少也适用于Java和.NET。
确定一个班级的“责任”是一个质的问题。
只看一个给定的班级代码,无论如何都不能给我们一个关于它如何处理它的可撤销性的想法。
至少根据我的经验,非常有必要考虑对类的需求更改如何传播到其他模块(或者其他类的更改如何传播到此类)。
由于@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。
从表面上看,很明显,班级对一件事情负责:电子表格。它与文档管理问题域中的其他实体(如Word处理)有所区别。
但是,请考虑电子表格对象可能更改的原因。
电子表格模型可能会有变化。这会影响加载并保存代码,但不会影响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归结为问'会发生什么变化?和'会受到什么影响'。当“什么可以改变”只映射到一个受影响的东西时,你就有了实现SRP原则的类。