軟件設(shè)計(jì)的五大原則_第1頁
軟件設(shè)計(jì)的五大原則_第2頁
軟件設(shè)計(jì)的五大原則_第3頁
軟件設(shè)計(jì)的五大原則_第4頁
軟件設(shè)計(jì)的五大原則_第5頁
已閱讀5頁,還剩46頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

軟件設(shè)計(jì)中的5大原則1.單一職責(zé)原則(SRP)陳述:就一個(gè)類而言,應(yīng)該只有一個(gè)導(dǎo)致其變化的原因分析:一個(gè)職責(zé)就是一個(gè)變化的軸線一個(gè)類如果承擔(dān)的職責(zé)過多,就等于將這些職責(zé)耦合在一起。一個(gè)職責(zé)的變化可能會(huì)虛弱或者抑止這個(gè)類完成其它職責(zé)的能力多職責(zé)將導(dǎo)致脆弱性的臭味Rectangle+draw()+area():doubleComputationalGeometryApplicationGraphicalApplicationGUIRectangle類具有兩個(gè)職責(zé):計(jì)算矩形面積的數(shù)學(xué)模型將矩形在一個(gè)圖形設(shè)備上描述出來示例1:Rectangle類違反了SRP,具有兩個(gè)職能——計(jì)算面積和繪制矩形這種對(duì)SRP的違反將導(dǎo)致兩個(gè)方面的問題:包含不必要的代碼一個(gè)應(yīng)用可能希望使用Retangle類計(jì)算矩形的面積,但是卻被迫將繪制矩形相關(guān)的代碼也包含進(jìn)來一些邏輯上毫無關(guān)聯(lián)的原因可能導(dǎo)致應(yīng)用失敗如果GraphicalApplication的需求發(fā)生了變化,從而對(duì)Rectangle類進(jìn)行了修改。但是這樣的變化居然會(huì)要求我們重新構(gòu)建、測(cè)試以及部署ComputationalGeometryApplication,否則其將莫名其妙的失敗。修改后的設(shè)計(jì)如下:Modem類(可能)有兩個(gè)職責(zé):撥號(hào)通信示例2:一個(gè)Modem的接口:ClassModem{ public: virtualvoiddail(char*pno)=0; virtualvoidhangup()=0; virtualvoidsend(charc)=0; virtualvoidrecv()=0;};什么是職責(zé)?

職責(zé)是“變化的原因”。上面的例子可能存在兩種變化的方式:連接和通信可能獨(dú)立變化 在這種情況下,應(yīng)該將職責(zé)分開。例如,應(yīng)用的變化導(dǎo)致了連接部分方法的簽名(signature)發(fā)生了變化,那么使用數(shù)據(jù)連接的部分也需要重新編譯、部署,這會(huì)相當(dāng)麻煩,使得設(shè)計(jì)僵化。連接和通信同時(shí)變化 這種情況下,不必將職責(zé)分開。反而分離可能導(dǎo)致“不必要的復(fù)雜性”的臭味刻舟求劍是錯(cuò)誤的。

——王亞沙修改后的設(shè)計(jì)如下: 有一點(diǎn)需要注意:在ModemImplementation中實(shí)際還是集合了兩個(gè)職責(zé)。這是我們不希望的,但是有時(shí)候卻是必須的。 但是我們注意到,對(duì)于應(yīng)用的其它部分,通過接口的分離我們已經(jīng)實(shí)現(xiàn)了職責(zé)的分離。 ModemImplementation已經(jīng)不被其它任何程序所依賴。除了main以外,其他所有程序都不需要知道這個(gè)函數(shù)的存在。

常見錯(cuò)誤提醒:持久化與業(yè)務(wù)規(guī)則的耦合。例如: 業(yè)務(wù)規(guī)則經(jīng)常變化,而持久化方法卻一般不變。將這兩個(gè)職責(zé)耦合在一起,將導(dǎo)致每次因?yàn)闃I(yè)務(wù)規(guī)則變化調(diào)整Employee類時(shí),所有持久化部分的代碼也要跟著變化

2.開放封閉原則(OCP)陳述:軟件實(shí)體(類、模塊、函數(shù)等)應(yīng)該是可以擴(kuò)展的,同時(shí)還可以是不必修改的,更確切的說,函數(shù)實(shí)體應(yīng)該: (1)對(duì)擴(kuò)展是開放的 當(dāng)應(yīng)用的需求變化時(shí),我們可以對(duì)模塊進(jìn)行擴(kuò)展,使其具有滿足改變的新的行為——即,我們可以改變模塊的功能 (2)對(duì)更改是封閉的 對(duì)模塊進(jìn)行擴(kuò)展時(shí),不必改動(dòng)已有的源代碼或二進(jìn)制代碼。分析:世界是變化的(而且變化很快),軟件是對(duì)現(xiàn)實(shí)的抽象 軟件必須能夠擴(kuò)展如果任何修改都需要改變已經(jīng)存在的代碼,那么可能導(dǎo)致牽一發(fā)動(dòng)全身現(xiàn)象,進(jìn)而導(dǎo)致雪崩效應(yīng),使軟件質(zhì)量顯著下降實(shí)現(xiàn)OCP的關(guān)鍵是抽象:例子1classclient{ server&s;public: client(server&SER):s(SER){} voiduseServer(){ s.ServerFunc(); }};classserver{ intserverData;public: voidServerFunc();};例子1(續(xù)) 這個(gè)程序出了什么問題?

client和server都是具體類,接口與實(shí)現(xiàn)沒有實(shí)現(xiàn)分離。如果我們想要讓client調(diào)用一個(gè)新的server類,那么我們不得不修改client的源代碼

從而帶來編譯、鏈接、部署等一系列的問題。見下頁程序2.開放封閉原則(OCP)例子1(續(xù)) classclient{

server&s;public: client(server&SER):s(SER){} voiduseServer(){ s.ServerFunc(); }};classserver{ intserverData;public: voidServerFunc();};classserver1{ intserverData;public: voidServerFunc();};classclient{ server1&s;public: client(server&SER):s(SER){} voiduseServer(){ s.ServerFunc(); }};2.開放封閉原則(OCP)例子1(續(xù)) 修改后的設(shè)計(jì)classclient{ ClientInterface&ci;public: client(ClientInterface&CI):ci(CI){} voiduseServer(){ ci.ServerFunc(); }};classClientInterface{ virtualvoidServerFunc()=0;};classserver:publicClientInterface{ intserverData;public: voidServerFunc();};例子1(續(xù))一個(gè)問題: 為什么上述的ClientInterface這個(gè)類要取這么個(gè)名字,叫做AbastractServer豈不更好?? 其實(shí)這里面蘊(yùn)含了一個(gè)思想:

——client類中更多的描述了高層的策略,而Server類中是對(duì)這些策略的一種具體實(shí)現(xiàn)。

而接口是策略的一個(gè)組成部分,他根client端的關(guān)系更加密切

我們應(yīng)該這樣想問題:ClientInterface中定義了client期 望Server做什么,而server具體類是對(duì)client這種要求的 一種具體實(shí)現(xiàn)。

OCP原則其實(shí)是要求我們清晰的區(qū)分策略和策略的具體實(shí)現(xiàn)形式。允許 擴(kuò)展具體的實(shí)現(xiàn)形式(開放),同時(shí)將這種擴(kuò)展與策略隔離開來,使 其對(duì)上層的策略透明(封閉)。

例子2 C語言程序 ---------shape.h-----------------emumShapeType{circle,square};structShape{ ShapeTypeitsType;};---------circle.h-----------------structCircle{ ShapeTypeitsType; doubleitsRadius; CPointitscenter;};---------square.h-----------------structSquare{ ShapeTypeitsType; doubleitsSide; CPointitsTopLeft;};---------drawAllShapes.cpp----------typedefstructShape*ShapePointer;voidDrawAllShapes(ShapePointerlist[],intn){ inti; for(i=0;i<n;i++){ structShape*s=list[i]; switch(s->itsType){ casesquare: s->Square(); break; casecircle: s->DrawCircle(); break; }}}例子2(續(xù))批判 這個(gè)程序不符合OCP,如果需要處理的幾何圖形中再加入“三角形”將引發(fā)大量的修改僵化的 增加Triangle會(huì)導(dǎo)致Shape、Square、Circle以及DrawAllShapes的重新編譯和部署脆弱的 因?yàn)榇嬖诖罅康募入y以查找又難以理解的Switch和If語句,修改稍有不慎,程序就會(huì)莫明其妙的出錯(cuò)牢固的 想在一個(gè)程序中復(fù)用DrawAllShapes,都必須帶上Circle、Square,即使那個(gè)程序不需要他們例子2(續(xù))修改后的設(shè)計(jì) classShape{public: virtualvoidDraw()const=0;};classSquare:publicShape{public: virtualvoidDraw()const;};classCircle:publicShape{public: virtualvoidDraw()const;};voidDrawAllShapes(Vector<Shape*>&list){vector<Shape*>::iteratori;for(i=list.begin();i!=list.end();i++) (*i)->Draw();}例子2(續(xù))再看這些批判 再加入“三角形”將變得十分簡單:僵化的 增加Triangle會(huì)導(dǎo)致Shape、Square、Circle以及DrawAllShapes的重新編譯和部署脆弱的 因?yàn)榇嬖诖罅康募入y以查找又難以理解的Switch和If語句,修改稍有不慎,程序就會(huì)莫明其妙的出錯(cuò)牢固的 想在一個(gè)程序中復(fù)用DrawAllShapes,都必須帶上Circle、Square,即使那個(gè)程序不需要他們謊言:上述代碼并不完全封閉——“如果我們希望正方形在所有圓之前繪制”會(huì)怎么樣?

——對(duì)繪圖的順序無法實(shí)現(xiàn)封閉

更糟糕的是,剛才的設(shè)計(jì)反而成為了實(shí)現(xiàn)“正方形在所有圓之前繪制”功能的障礙。真實(shí)的謊言:一般而言,無論模塊多么“封閉”,都會(huì)存在一些無法對(duì)之封閉的變化

沒有對(duì)所有變化的情況都封閉的模型我們?cè)趺崔k?既然不可能完全封閉,我們必須有策略的對(duì)待此問題——對(duì)模型應(yīng)該封閉那類變化作出選擇,封閉最可能出現(xiàn)的變化

這需要對(duì)領(lǐng)域的了解,豐富的經(jīng)驗(yàn)和常識(shí)

錯(cuò)誤的判斷反而不美,因?yàn)镺CP需要額外的開銷(增加復(fù)雜度)

敏捷的思想——我們預(yù)測(cè)他們,但是直到我們發(fā)現(xiàn)他們才行動(dòng)回到例2:要實(shí)現(xiàn)對(duì)排序的封閉應(yīng)該如何設(shè)計(jì)?classShape{ public: virtualvoidDraw()const=0; virtualboolPrecedes(constShape&)const=0; booloperator<constShape&s){returnPrecedes(s);}};template<typenameP>classLessp{ public:booloperator(){constPp,constPq){return(*p)<(*q);}}voidDrawAllShapes(vector<Shape*>&list){ vector<Shape*>orderedList=list; sort(orderedList.begin(),orderedList.end(),Lessp<Shape*>()); vector<Shape*>::const_iteratorI; for(i=orderedList.begin();i!=orderedList.end();i++) (*i)->Draw();}對(duì)于各個(gè)Shape的派生類,需要實(shí)現(xiàn)具體的排序規(guī)則Circle類的排序規(guī)則實(shí)現(xiàn)如下:BoolCircle::Precedes(constShape&s)const{ if(dynamic_cast<Square*>(s)) returntrue; else returnfalse;}這個(gè)程序符合OCP嗎??利用“數(shù)據(jù)驅(qū)動(dòng)”的方法獲得封閉性#include<typeinfo>#include<string>#include<iostream>usingnamespacestd;classShape{public: virtualvoidDraw()const=0; virtualboolPrecedes(constShape&)const; booloperator<(constShape&s)const{ returnPrecedes(s); }private: staticchar*typeOrderTable[];};char*Shape::typeOrderTable[]={ typeid(Circle).name(), typeid(Square).name(), 0};boolShape::Precedes(constShape&s)const{ constchar*thisType=typeid(*this).name(); constchar*argType=typeid(s).name(); booldone=false; intthisOrd=-1; intargOrd=-1; for(inti=0;!done;i++){ constchar*tableEntry=typeOrderTable[i]; if(tableEntry!=0){ if(strcmp(tableEntry,thisType)==0) thisOrd=i; if(strcmp(tableEntry,argType)==0) argOrd=i; if((argOrd>0)&&(thisOrd>0)) done=true; } else//tableentry==0 done=true; } returnthisOrd<argOrd;}通過上述方法,我們成功地做到了一般情況下DrawAllShapes函數(shù)對(duì)于順序問題的封閉,也使得每個(gè)Shape派生類對(duì)于新的Shape派生類的創(chuàng)建者或者給予類型的Shape對(duì)象排序規(guī)則的改變是封閉的。對(duì)于不同的Shapes的繪制順序的變化不封閉的唯一部分就是表本身??梢园驯矸胖迷谝粋€(gè)單獨(dú)的模塊中,和所有其他模塊隔離,因此對(duì)于表的改動(dòng)不會(huì)影響其他任何模塊。事實(shí)上在C++中我們可以在鏈接時(shí)選擇要使用的表。3.LisKov替換原則(LSP)陳述:子類型(Subtype)必須能夠替換他們的基類型(Basetype) BarbaraLiskov對(duì)原則的陳述: 若對(duì)每個(gè)類型S的對(duì)象o1,都存在一個(gè)類型T的對(duì)象o2,使得在所有針對(duì)T編寫的程序P中,用o1替換o2后,程序P的行為功能不變,則S是T的子類型。分析:違法這個(gè)職責(zé)將導(dǎo)致程序的脆弱性和對(duì)OCP的違反 例如:基類Base,派生類Derived,派生類實(shí)例d,函數(shù)f(Base*p);f(&d) 會(huì)導(dǎo)致錯(cuò)誤 顯然D對(duì)于f是脆弱的。如果我們?cè)噲D編寫一些測(cè)試,以保證把d傳給f時(shí)可以使f具有正確的行為。那么這個(gè)測(cè)試違反了OCP——因?yàn)閒無法對(duì)Base的所有派生類都是封閉的示例1:structPoint{doublex,y;};structshape{ enumShapeType{square,circle}itsType; shape(ShapeTypet):itsType(t){}};structCircle:publicShape{ Circle():Shape(circle){}; voidDraw()const; PointitsCenter; doubleitsRadius;};structSquare:publicShape{ Square():Shape(square){}; voidDraw()const; PointitsTopLeft; doubleitsSide;};voidDrawShape(constShape&s){ if(s.itsType==Shape::square) static_cast<constSquare&>(s).Draw(); elseif(s.itsType==Shape::circle) static_cast<constCircle&>(s).Draw();} 顯然,DrawShape違反了OCP, 為什么?

因?yàn)镃ircle和Square違反了LSP示例2:一次更加奇妙的違規(guī)classRectangle{ PointtopLeft; doulbewidth; doubleheight;public: voidsetWidth(doublew){width=w;} voidsetHeight(doubleh){height=h;} doublegetWidth()const{returnwidth;} doublegetHeight()const{returnheight;}};classSquare:publicRectangle{public: voidsetWidth(doublew); voidsetHeight(doubleh);};voidSquare::setWidth(doublew){ Rectangle::setWidth(w); Rectangle::setHeight(w);};voidSquare::setHeight(doubleh){ Rectangle::setWidth(h); Rectangle::setHeight(h);};問題的第一步分析:看下面這個(gè)函數(shù)voidf(Rectangle&r){ r.SetWidth(32);}問題:顯然,當(dāng)我們將一個(gè)Square的實(shí)例傳給f時(shí),將可能導(dǎo)致其height與width不等,破壞了其完整性——違反了LSP要改正上述問題,很簡單,我們只要將SetWidth和SetHeight兩個(gè)函數(shù)設(shè)置成virtual函數(shù)即可——添加派生類需要修改基類,通常意味著設(shè)計(jì)上的缺陷但是并非所有人都同意上述的分析反方:真正的設(shè)計(jì)缺陷是忘記把SetWidth和SetHeight兩個(gè)函數(shù)作為virtual函數(shù)正方:設(shè)置長方形的長寬是非常基本的操作,不是預(yù)見到有正方形這樣的派生類,怎么會(huì)想到要將其設(shè)成虛函數(shù)?放下這個(gè)爭(zhēng)論,我們先將SetWidth和SetHeight改作虛函數(shù)看看classRectangle{ PointtopLeft; doulbewidth; doubleheight;public:

virtualvoidsetWidth(doublew){width=w;}

virtualvoidsetHeight(doubleh){height=h;} doublegetWidth()const{returnwidth;} doublegetHeight()const{returnheight;}};classSquare:publicRectangle{public: voidsetWidth(doublew); voidsetHeight(doubleh);};voidSquare::setWidth(doublew){ Rectangle::setWidth(w); Rectangle::setHeight(w);};voidSquare::setHeight(doubleh){ Rectangle::setWidth(h); Rectangle::setHeight(h);};看起來,很不錯(cuò)!真正的問題:voidg(Rectangle&r){ r.setWidth(5); r.setHeight(4); assert(r.Area()==20);}函數(shù)g不能操作Square的實(shí)例,Square不能替換Rectangle,所以違反了LSPLSP告訴我們:孤立的看,我們無法判斷模型的有效性——考慮一個(gè)設(shè)計(jì)是否恰當(dāng)時(shí),不能孤立的看待并判斷,應(yīng)該從此設(shè)計(jì)的使用者所作出的假設(shè)來審視它!事先的推測(cè)是困難的,我們采用敏捷的思想推遲這個(gè)判斷——“一個(gè)模型是否違反LSP”。直到出現(xiàn)問題的時(shí)候我們才解決它。更加深入的思索:這個(gè)看似明顯正確的模型怎么會(huì)出錯(cuò)呢?“正方形是一種長方形”——地球人都知道錯(cuò)在哪里? 對(duì)不是g函數(shù)的編寫者而言,正方形可以是長方形,但是對(duì)g函數(shù)的編寫者而言,Square絕對(duì)不是Rectangle??!

OOD中對(duì)象之間是否存在IS-A關(guān)系,應(yīng)該從行為的角度來看待。

而行為可以依賴客戶程序做出合理的假設(shè)?;谄跫s(和約)的設(shè)計(jì)——DBC(DeignbyContract)“合理的假設(shè)”使人郁悶。

——我怎么知道是否合理呢??使用DBC,類的編寫者需要顯示的規(guī)定針對(duì)該類的契約??蛻舸a的編寫者可以通過契約獲悉行為的依賴方式。契約通過為每一個(gè)方法規(guī)定前置條件(preconditions)和后置條件(postconditions)來指定的。要使一個(gè)方法執(zhí)行,前置條件一定要為真(對(duì)客戶的要求);函數(shù)執(zhí)行后要保證后置條件為真(對(duì)函數(shù)編寫者的要求)?;谄跫s(和約)的設(shè)計(jì)——DBC(DeignbyContract)(續(xù))例如: 在上面的例子中,Rectangle::SetWidth(doublew)的后置條件可以看作是:

assert((itsWidth==w)&&(itsHeight==old.itsHeight));基類和派生類在前置條件和后置條件上的關(guān)系是:

如果在派生類中重新申明了基類中已有的成員函數(shù),這個(gè)函數(shù)只能使用相等或更弱的前置條件來替換原有的前置條件;并且,只能使用相等或更強(qiáng)的后置條件來替換原有的后置條件。

派生類必須接受基類已經(jīng)接受的一切;并且,派生類不能違反基類已經(jīng)確定的規(guī)則。在一些語言中明確的支持契約,例如Eiffel,你申明它們,運(yùn)行時(shí)系統(tǒng)會(huì)自動(dòng)的檢查。在Jave和C++標(biāo)準(zhǔn)中尚未支持,我們必須自己考慮。4.依賴倒置原則(DIP)陳述:高層模塊不應(yīng)該依賴于低層模塊。二者應(yīng)該依賴于抽象。抽象不應(yīng)該依賴于細(xì)節(jié)。細(xì)節(jié)應(yīng)該依賴于抽象。分析:所謂“倒置”是相對(duì)于傳統(tǒng)的開發(fā)方法(例如結(jié)構(gòu)化方法)中總是傾向于讓高層模塊依賴于低層模塊而言的軟件結(jié)構(gòu)而言的。高層包含應(yīng)用程序的策略和業(yè)務(wù)模型,而低層包含更多的實(shí)現(xiàn)細(xì)節(jié),平臺(tái)相關(guān)細(xì)節(jié)等。高層依賴低層將導(dǎo)致:難以復(fù)用。通常改變一個(gè)軟硬件平臺(tái)將導(dǎo)致一些具體的實(shí)現(xiàn)發(fā)生變化,如果高層依賴低層,這種變化將導(dǎo)致逐層的更改。難以維護(hù)。低層通常是易變的。 層次化:“……所有良構(gòu)的OO體系結(jié)構(gòu)都具有清晰的層次定義,每個(gè)層次通過一個(gè)定義良好的、受控的接口向外提供了一組內(nèi)聚的服務(wù)。”

——Booch對(duì)上述論述可能存在兩種不同的理解:簡單的理解u1()u2()g(){u1();u2();}p(){g();}層次化(續(xù)):更好的理解依賴關(guān)系倒置 下層的實(shí)現(xiàn),依賴于上層的接口接口所有權(quán)倒置 客戶擁有接口,而服務(wù)者則從這些接口派生依賴不倒置的開發(fā)自頂向下首先設(shè)計(jì)整個(gè)軟件的分解結(jié)構(gòu)然后首先實(shí)現(xiàn)下層的功能再實(shí)現(xiàn)上層的功能,并使上層調(diào)用下層函數(shù)依賴倒置的開發(fā)首先設(shè)計(jì)上層需要調(diào)用的接口,并實(shí)現(xiàn)上層然后低層類從上層接口派生,實(shí)現(xiàn)低層接口屬于上層示例1(Button與Lamp):Button(開關(guān))感知外界的變化。 當(dāng)接受到Poll(輪詢)消息時(shí),判斷其是否被“按下”。這個(gè)按下是抽象的(不關(guān)心通過什么樣的機(jī)制去感知):可能是GUI上的一個(gè)按鈕被鼠標(biāo)單擊可能是一個(gè)真正的按鈕被手指按下可能是一個(gè)防盜裝置檢測(cè)到了運(yùn)動(dòng)……Lamp(燈)根據(jù)指示,收到turnon消息顯示某種燈光,收到turnoff消息關(guān)閉燈光可能是計(jì)算機(jī)控制臺(tái)的LED可能是停車場(chǎng)的日光燈可能是激光打印機(jī)中的激光……應(yīng)該如何設(shè)計(jì)程序來用Button控制Lamp呢?

一個(gè)不成熟的設(shè)計(jì)

Button對(duì)象直接依賴Lamp對(duì)象,從而:Lamp的任何變化都會(huì)影響到Button,導(dǎo)致其改寫或者重新編譯黑盒方式重用Button來控制一個(gè)Motor類變得不可能classButton{ Lamp*itsLamp;public: voidpoll(){ if(/*somecondition*/) itsLamp->turnOn(); .... }};一個(gè)依賴倒置的設(shè)計(jì) 依賴于抽象什么是高層策略?就是應(yīng)用背后的抽象 背后的抽象是檢測(cè)用戶的開/關(guān)指令用什么機(jī)制檢測(cè)用戶的指令?無關(guān)緊要目標(biāo)對(duì)象是什么?無關(guān)緊要他們不會(huì)影響到抽象的具體細(xì)節(jié)改進(jìn)后的設(shè)計(jì):

Button依賴于抽象的接口ButtonServer(向該接口發(fā)消息)。ButtonServer提供一些抽象的方法,Button類通過這些接口可以開啟或關(guān)掉一些東西。Lamp也依賴于ButtonServer接口(從此接口派生),提供具體的實(shí)現(xiàn)。部分代碼://Button.h#include"ButtonServer.h"classButton{ ButtonServer*bs;public: voidpoll();};//Button.cppvoidButton::poll(){ if(/*mechanismfordetectingturnOncommand*/) bs->turnOn(); elseif((/*mechanismfordetectingturnOffcommand*/) bs->turnOff();}//ButtonServer.hclassButtonServer{public: virtualvoidturnOn()=0; virtualvoidturnOff()=0;};//lamp.hclassLamp:publicButtonServer{public: voidturnOn(); voidturnOff();};//lamp.cppvoidLamp::turnOn(){ /*codesforturnonaspecificdevice*/}voidLamp::turnOff(){ /*codesforturnoffaspecificdevice*/}分析:上述設(shè)計(jì)使得Button可以控制所有愿意實(shí)現(xiàn)ButtonServer接口的設(shè)備,甚至是一個(gè)尚未開發(fā)出來的設(shè)備。質(zhì)疑:這樣的設(shè)計(jì)是不是強(qiáng)加了這樣一個(gè)約束——所有需要被Button控制的對(duì)象一定要實(shí)現(xiàn)ButtonServer類。如果我的設(shè)備還希望能夠被另一個(gè)對(duì)象控制,比如Switch控制,怎么辦?這種設(shè)計(jì)是不是將Button對(duì)Lamp的依賴轉(zhuǎn)嫁成了Lamp對(duì)Button的依賴呢?(畢竟Lamp只能被一種Button控制也是不好的)抗辯:上述質(zhì)疑不成立。Button依賴于ButtonServer接口,但是接口并不依賴于Button,也就是說任何知道如何操作ButtonServer接口的對(duì)象都可以操作Lamp。也許需要改進(jìn)的僅僅是ButtonServer這樣一個(gè)有些“誤導(dǎo)性”的名字,我們可以將這個(gè)名字該得更加抽象一些,例如:SwitchableDevice5.接口隔離原則(ISP)陳述:不應(yīng)該強(qiáng)迫客戶依賴于他們不用的方法一個(gè)類的不內(nèi)聚的“胖接口”應(yīng)該被分解成多組方法,每一組方法都服務(wù)于一組不同的客戶程序。先說一個(gè)例子:classDoor{ public: virtualvoidLock()=0;

virtualvoidUnlock()=0; vi

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論