我正在尋找一些違反單一職責原則的代碼。不要告訴我從鮑勃叔叔的書籍或網站的任何實例,因爲這些都貼滿所有在互聯網上,像這樣的:您違反單一責任原則的最佳範例是什麼?
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原則的類。