SRP:?jiǎn)我宦氊?zé)的原則
一、定義。
SRP(Single Responsibility Principle):?jiǎn)我宦氊?zé)的原則:一個(gè)類應(yīng)該只有一個(gè)發(fā)生變化的原因。
每一個(gè)職責(zé)都是變化的軸線。當(dāng)需求變化時(shí),該變化會(huì)反應(yīng)為類的職責(zé)變化。如果一個(gè)類承擔(dān)了多于一個(gè)的職責(zé),那么引起它變化的原因就會(huì)有多個(gè)。
如果一個(gè)類承擔(dān)的職責(zé)過多,就等于把這些職責(zé)耦合在了一起。一個(gè)職責(zé)的變化可能會(huì)消弱或者抑制這個(gè)類完成其他職責(zé)的能力。這種耦合會(huì)導(dǎo)致脆弱的設(shè)計(jì),當(dāng)發(fā)生變化時(shí),設(shè)計(jì)會(huì)遭受到意想不到的破壞。
如下圖的設(shè)計(jì)。Rectangle類具有兩個(gè)方法,一個(gè)方法把矩形繪制在屏幕上,另一個(gè)方法計(jì)算矩形的面積。
有兩個(gè)不同的應(yīng)用程序使用Rectangle類,一個(gè)應(yīng)用程序是有關(guān)計(jì)算幾何學(xué)方面的,利用Rectangle類計(jì)算幾何形狀,但不會(huì)在屏幕上繪制矩形。另外一個(gè)應(yīng)用程序?qū)嵸|(zhì)上是有關(guān)圖形繪制方面的,它可能也會(huì)進(jìn)行一些計(jì)算幾何學(xué)方面的工作,但是他肯定會(huì)在屏幕上繪制矩形。
這個(gè)設(shè)計(jì)違反了單一職責(zé)的原則(SRP)。Rectangle類具有兩個(gè)職責(zé)。
第一:提供了一個(gè)矩形幾何形狀的數(shù)學(xué)模型;
第二:把矩形在一個(gè)圖形用戶界面上繪制出來。
導(dǎo)致的問題:
首先,我們必須在計(jì)算幾何應(yīng)用程序中包含進(jìn)GUI代碼。在.NET中,就必須要把GUI組建和計(jì)算幾何應(yīng)用一起構(gòu)建、部署。
其次,如果GraphicalApplication的改變由于一些原因?qū)е铝薘ectangle的改變,那么這個(gè)改變會(huì)迫使我們重新構(gòu)建、測(cè)試以及部署ComputationalGeometryApplication。如果忘記了這樣做,ComputationalGeometryApplication可能會(huì)有不可預(yù)測(cè)的問題。
一個(gè)較好的設(shè)計(jì)是把這兩個(gè)職責(zé)分離到下圖中所示的兩個(gè)完全不同的類中。
二、定義職責(zé)
在SRP中,我們把職責(zé)定義為變化的原因。如果你能夠想到多于一個(gè)的動(dòng)機(jī)去改變一個(gè)類,那么這個(gè)類就具有多于一個(gè)的職責(zé)。
如下代碼中Modem的接口,大都數(shù)人都會(huì)認(rèn)為這個(gè)接口看起來非常合理。該接口所聲明的4個(gè)方法確實(shí)是調(diào)制解調(diào)器所具有的功能。
public interface IModem
{
void Dial(string pno);
void Hangup();
void Send(char c);
char Recv();
}
然而,該接口中卻顯示出兩個(gè)職責(zé)。第一:鏈接管理;第二:數(shù)據(jù)通信。Dial和Hangup方法進(jìn)行調(diào)制解調(diào)器的鏈接處理,而Send和recv方法進(jìn)行數(shù)據(jù)通信。
這兩個(gè)職責(zé)應(yīng)該分開嗎?這依賴于應(yīng)用程序的變化方式。如果應(yīng)用程序的變化會(huì)影響到鏈接方法的簽名(signature),那么這個(gè)設(shè)計(jì)就具有僵化性的臭味,因?yàn)檎{(diào)用Send和Recv的類必須要重新編譯、部署的次數(shù)常常會(huì)超過我們希望的次數(shù)。在這種情況下,這兩個(gè)職責(zé)應(yīng)該被分離,如下圖。這樣做避免了客戶應(yīng)用程序和這兩個(gè)職責(zé)耦合在一起。
另一方面,如果應(yīng)用程序的變化方式總是導(dǎo)致這兩個(gè)職責(zé)同時(shí)變化,那么就不必分離他們。這時(shí),分離它們就會(huì)具有不必要的復(fù)雜性的臭味。
僅當(dāng)變化發(fā)生時(shí),變化的軸線(職責(zé))才具有實(shí)際的意義。
我們把兩個(gè)職責(zé)都耦合進(jìn)了ModemImplementation類中,這不是所希望的,但或許是必要的,常常由于一些和硬件或者操作系統(tǒng)的細(xì)節(jié)有關(guān)的原因,迫使我們這樣去處理。我們可以把它看做一個(gè)有缺陷的類,所有的依賴關(guān)系都是從它出發(fā),誰也不需要依賴它。除了Main以為,誰也不需要知道它的存在。因此我們已經(jīng)把丑陋的部分隱藏起來。




浙公網(wǎng)安備 33010602011771號(hào)