




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第1章內(nèi)容介紹和授課方法
1.1Java設(shè)計(jì)模式內(nèi)容介紹
1.1.1先看幾個(gè)經(jīng)典的面試題
(1)原型設(shè)計(jì)模式問(wèn)題
1)請(qǐng)使用fML類圖畫(huà)出原型模式核心角色
要點(diǎn):UML類圖(描述類與類之間的關(guān)系):原型模式
2)原型設(shè)計(jì)模式的深拷貝和淺拷貝是什么,并寫出深拷貝的兩種方式的源碼(重寫clono
方法實(shí)現(xiàn)深拷貝、使用序列化來(lái)實(shí)現(xiàn)深拷貝)
3)在Spring框架中哪里使用到原型模式,并對(duì)源碼進(jìn)行分析
beans,xml
<beanid="idOl"class=z,com.atguigu.spring,bean.Monster^scope="prototype”/)
答:Spring中原型bean的創(chuàng)建,就是原型模式的應(yīng)用。代碼分析+Debug源碼如下:
beans.xml
<bean\d="idOl"class="com.atguigu.spring.bean.Monster"scopet二一"
Test.java
Applicationcontextapplicationcontext=new
ClassPathXmlApplicationContext("beans.xml");
〃獲取monster[通過(guò)id獲取monster]b??n=g*t0bJ?ctForB?M>Xn?t4
Objectbean=applicationcontextean"idOl";
?1*?if^^>d.i*Prctotyp?()y(
SysXem.out.printlnf'bean"+〃!?>?,,?”?,;/Yr.X
ObjectprfttotypelnttaiK*■I
try(
b*forcPrototyp?Cr?ationi
publicObjectgetBean(Stringname)throwsBeansException(prototype!n*tancescrei
returndoGetBean(nante,null,null,false);finally(
)afterPr?t?typ*Cre?tion(l
(2)設(shè)計(jì)模式的七大原則
要求:
1)七大設(shè)計(jì)原則核心思想
2)能夠以類圖的說(shuō)明設(shè)計(jì)原則
3)在項(xiàng)目實(shí)際開(kāi)發(fā)中,你在哪里使用到了。cp原則(開(kāi)閉原則,在工廠模式里用到)
設(shè)計(jì)模式常用的七大原則有:?jiǎn)我宦氊?zé)原則、接口隔離原則、依賴倒轉(zhuǎn)原則、里式替
換原則、開(kāi)閉原則。cp、迪米特法則、合成復(fù)用原則(第7條在有的書(shū)上并沒(méi)有給出)批注[1]:
類圖如下:
puttKPioduetAcrMt^roducVMX
,tsrw?PraductAM”
puOhcProductsce?《Product8(X
IrcttfnMwPracuctfilO)J>
(3)金融借貸平臺(tái)項(xiàng)目
先看幾個(gè)經(jīng)典的設(shè)計(jì)模式面試題
金融盤筑壬臺(tái)項(xiàng)目:借貸平臺(tái)的訂單,有審核-
發(fā)布一搶單等等步驟,隨著操作的不同,會(huì)改
變訂單的轆,項(xiàng)目巾典灌次實(shí)現(xiàn)就會(huì)使用
到狀態(tài)模竄請(qǐng)你使哦態(tài)模印行設(shè)計(jì),并
完成實(shí)際代碼、一,
間題分析.
這類代瑪難以應(yīng)對(duì)變化,在添加一種狀態(tài)時(shí),
我們需要手動(dòng)添加if/else,在添加一種功能時(shí),
要對(duì)所有的狀態(tài)進(jìn)行判斷。因此代碼會(huì)變得鉞
來(lái)越臃腫,并且一旦沒(méi)有處理某個(gè)狀態(tài),便會(huì)
發(fā)生極其嚴(yán)重的BUG,難以維護(hù)
3
kAaags-^i
下圖是狀態(tài)轉(zhuǎn)換圖:
竄住
(4)解釋器設(shè)計(jì)模式
1)介紹解釋器設(shè)計(jì)模式是什么?
2)畫(huà)出解釋器設(shè)計(jì)模式的UML類圖,分析設(shè)計(jì)模式中的各個(gè)角色是什么?
3)請(qǐng)說(shuō)明Spring的框架中,哪里使用到了解釋器設(shè)計(jì)模式,并做源碼級(jí)別的分析
注:如果菱形是實(shí)心的,代表組合關(guān)系
Spring框架中Spe1ExpressionParser就使用到解釋器模式,代碼分析+Debug源碼+模式
角色分析說(shuō)明:
1)Spring框架中SpelExpressionParser就使用到解釋器模式
2)代碼分析+Debug源碼+模式角色分析說(shuō)明
publicinterfaceExpressionParser{
ExpressionparseExpression(Stnng
publicclassInterpreter(
expcessionString)throwsParseException;
ExpressionparseExpression(Slnngenng
publicstaticvoidmain(String[]args){
ParserContextcontext)throwsParse
?SpelExpressionParserparser=newSpelExpressionParser();
Expressionexpression=parsei.parseExp(ession(*100*(2+400),??一實(shí)現(xiàn)一
1+66)
intresult=(Integer)expre$sion.getValue();publicabstractdassTemplateAwareExpresuonParser
Systemout.println(result);implementsExpre$$ionPar$er{依鞍
publicExpfesitonparseExp?etsion(String
expressionString,Parsercontextcontext){//不同脩況
返回不同的Exprcs.)〃否源碼
繼承繼承
pubficclass
d?ssInternalSpHExpressionParser
extends
extends
TemplateAware£xpres$4onParser{
TcmolateAwarffxD>r$ionPar,erf
(5)單例設(shè)計(jì)模式
單例設(shè)計(jì)模式一共有幾種實(shí)現(xiàn)方式?請(qǐng)分別用代碼實(shí)現(xiàn),并說(shuō)明各個(gè)實(shí)現(xiàn)方式的優(yōu)點(diǎn)和
缺點(diǎn)?
單例設(shè)計(jì)模式一共有8種寫法,后面我們會(huì)依次講到:
1)俄漢式兩種
2)懶漢式三種
3)雙重檢查:多線程開(kāi)發(fā)時(shí)解決沖突問(wèn)題,還可以保證懶加載(?)
4)靜態(tài)內(nèi)部類:利用靜態(tài)內(nèi)部類的特點(diǎn),既實(shí)現(xiàn)了多線程的并發(fā)問(wèn)題,同時(shí)也解決
了懶加載的特點(diǎn)(在單例模式中用的也很多)
5)枚舉:經(jīng)典的單例設(shè)計(jì)模式(推薦使用)
1.1.2設(shè)計(jì)模式的重要性/應(yīng)用場(chǎng)景
(1)軟件工程中,設(shè)計(jì)模式(designpattern)是對(duì)軟件設(shè)計(jì)中普遍存在(反復(fù)出現(xiàn))
的各種問(wèn)題,所提出的解決方案,這個(gè)術(shù)語(yǔ)是由埃里希?伽瑪(ErichGamma)等人在
1990年代從建筑設(shè)計(jì)領(lǐng)域引入到計(jì)算機(jī)科學(xué)的。
(設(shè)計(jì)模式是為了讓軟件具有更好的復(fù)用性、擴(kuò)展性、可讀性、規(guī)范性和穩(wěn)定性等等)
(4)如果項(xiàng)目開(kāi)發(fā)完后,原來(lái)程序員離職,你接手維護(hù)該項(xiàng)目怎么辦?
(維護(hù)性:主要體現(xiàn)在可讀性、規(guī)范性)
(5)目前程序員門檻越來(lái)越高,一線IT公司(大廠),都會(huì)問(wèn)你在實(shí)際項(xiàng)目中使用過(guò)什
么設(shè)計(jì)模式,怎樣使用的,解決了什么問(wèn)題。
(6)設(shè)計(jì)模式在軟件中哪里?
面向?qū)ο螅?。。?>(項(xiàng)目的)功能模塊[設(shè)計(jì)模式+算法(數(shù)據(jù)結(jié)構(gòu))]=>框架[使用到多
種設(shè)計(jì)模式]=>架構(gòu)[服務(wù)器集群]
(7)如果想成為合格軟件工程師,那就花時(shí)間來(lái)研究下設(shè)計(jì)模式是非常必要的.
1.2課程亮點(diǎn)和授課模式
(1)設(shè)計(jì)模式很有用,其實(shí)也很好玩,很像小時(shí)候搭積木,怎樣搭建更加穩(wěn)定,堅(jiān)固
(2)設(shè)計(jì)模式很重要,因?yàn)榘芏嗑幊趟枷?,還是有一定難度的,我們努力做到通俗易
懂(設(shè)計(jì)模式不僅僅是站在實(shí)現(xiàn)某個(gè)功能的角度來(lái)思考的,而是站在怎么讓軟件結(jié)構(gòu)更合批注[2]:
理的角度)
(3)采用提出一個(gè)應(yīng)用場(chǎng)景引出設(shè)計(jì)模式剖析(設(shè)計(jì)模式的)原理->分析實(shí)現(xiàn)步驟
(圖解)-〉代碼實(shí)現(xiàn)-)框架或項(xiàng)目源碼分析(找到使用的地方)的步驟講解[比如:以建造
者模式為例]
A.提出一個(gè)實(shí)際需求:蓋房問(wèn)題
B.使用傳統(tǒng)的方式來(lái)完成
C.傳統(tǒng)的方式解決蓋房問(wèn)題分析,引出建造者模式
D.建造者模式原理分析
E.建造者模式原理結(jié)構(gòu)圖
F.建造者模式解決蓋房問(wèn)題思路分析+代碼實(shí)現(xiàn)(盡量配類圖)時(shí)比」
G.建造者模式在JDK、SSM的應(yīng)用和源碼分析
(4)課程目標(biāo):讓大家掌握本質(zhì),達(dá)能在工作中靈活運(yùn)用解決實(shí)際問(wèn)題和優(yōu)化程序結(jié)構(gòu)
的目的.
第2章設(shè)計(jì)模式七大原則
2.1設(shè)計(jì)模式的目的
編寫軟件過(guò)程中,程序員面臨著來(lái)自耦合性,內(nèi)聚性以及可維護(hù)性,可擴(kuò)展性,重
用性,靈活性等多方面的挑戰(zhàn),設(shè)計(jì)模式是為了讓程序(軟件)具有更好的
1)代碼重用性(即:相同功能的代碼,不用多次編寫)
2)可讀性(即:編程規(guī)范性,便于其他程序員的閱讀和理解)
3)可擴(kuò)展性(即:當(dāng)需要增加新的功能時(shí),非常的方便,也稱為可維護(hù)性)
4)可靠性(即:當(dāng)我們?cè)黾有碌墓δ芎?,?duì)原來(lái)的功能沒(méi)有影響)
5)使程序呈現(xiàn)高內(nèi)聚,低耦合的特性。(即:模塊內(nèi)部是非常緊密的,但是模塊與
模塊之間/功能與功能之間的耦合性很低)
分享金句:
設(shè)計(jì)模式包含了面向?qū)ο蟮木?,“懂「設(shè)計(jì)模式,你就懂J'面向?qū)ο蠓治龊驮O(shè)計(jì)
(OOA/D)的精要”批注[3]:懂了設(shè)計(jì)模式,你就懂了面向?qū)ο蠓治龊驮O(shè)
ScottMciyers在其巨著《EffectiveC++》就曾經(jīng)說(shuō)過(guò):C++老手和C++新手的區(qū)別就計(jì)的精要。
是前者手背上有很多傷疤。
2.2設(shè)計(jì)模式七大原則
設(shè)計(jì)模式原則,其實(shí)就是程序員在編程時(shí)應(yīng)當(dāng)遵守的原則,也是各種設(shè)計(jì)模式的基礎(chǔ)
(即:設(shè)計(jì)模式為什么這樣設(shè)計(jì)的依據(jù))。
設(shè)計(jì)模式常用的七大原則有:
(1)單一職責(zé)原則
(2)接口隔離原則
(3)依賴倒轉(zhuǎn)(倒置)原則
(4)里式替換原則
(5)開(kāi)閉原則
(6)迪米特法則
(7)合成復(fù)用原則
2.3單一職責(zé)原則
2.3.1基本介紹
對(duì)類來(lái)說(shuō)的,即一個(gè)類應(yīng)該只負(fù)責(zé)一項(xiàng)職責(zé)(注意:一項(xiàng)職責(zé)!=只有一個(gè)方法)。
如類A負(fù)責(zé)兩個(gè)不同職責(zé):職責(zé)1,職責(zé)2。當(dāng)職責(zé)1需求變更而改變A時(shí),可能造成
職責(zé)2執(zhí)行錯(cuò)誤,所以需要將類A的粒度分解為Al,A2o
2.3.2應(yīng)用實(shí)例
以交通工具案例講解。
(1)方案一
packagecom.principle,singleresponsibility;
publicclassSingleResponsibilityl{
publicstaticvoidmain(String[]args){
Vehiclevehicle=newVehicleO;
vehicle.run("摩托車");
vehicle,run("汽車");
vehicle,run("飛機(jī)”);
}
)
〃交通工具類
〃方案一:無(wú)論是哪種交通工具,run()方法都輸出“在公路上運(yùn)行”,這違反了單一
職責(zé)原則
〃解決方案:根據(jù)交通工具運(yùn)行的方法按不同,分解成不同的類
classVehicle{
publicvoidrun(Stringvehicle){
System.out.printIn(vehicle+”在公路上運(yùn)行...”);
}
?
(2)方案二
publicclassSing1eResponsibi1ity2{
publicstaticvoidmain(String口args){
RoadVehicleroadvehicle=newRoadVehicleO;
roadvehicle,run("摩托車");
roadvehicle,run("汽車");
AirVehicleairvehicle=newAirVehicleO;
airvehicle,run(“飛機(jī)”);
}
)
〃方案二的分析
〃L嚴(yán)格遵守了單?職責(zé)原則,但是這樣做改動(dòng)很大,即:將類分解的同時(shí)還要修改
客戶端,成本太高
〃2.改進(jìn):直接修改Vehicle類,改動(dòng)的代碼比較少
classRoadVehicle{
publicvoidrun(Stringvehicle){
System.out.printin(vehicle+”在公路上運(yùn)行...”);
}
)
classAirVehicle{
publicvoidrun(Stringvehicle){
System,out.printin(vehicle+”在天空中運(yùn)行...;
classWaterVehicle{
publicvoidrun(Stringvehicle){
System.out.printin(vehicle+”在水中運(yùn)行...;
}
)
(3)方案三
publicclassSingleResponsibi1ity3{
publicstaticvoidmain(String[]args){
Vehicle2vehicle2=newVehicle2();
vehicle2.run(“摩托車”);
vehicle2.runAir("飛機(jī)”);
vehicle2.runWater("輪船”);
}
)
〃方案三的分析
〃1.這種修改方法沒(méi)有對(duì)原來(lái)的類(方法一)做大的修改,只是增加了方法
〃2.雖然沒(méi)有在類的級(jí)別卜.遵守單一職責(zé)原則,但是在方法級(jí)別上仍然遵守單一職責(zé)
原則
〃后續(xù)在每個(gè)方法中可能還會(huì)有其他處理,注意,要慎用if..else..(用類來(lái)化解多分
枝)
classVehicle2{
publicvoidrun(Stringvehicle){
System,out.printin(vehicle+”在公路上運(yùn)行...”);
)
publicvoidrunAir(Stringvehicle){
System.out.printin(vehicle+”在空中運(yùn)行...”);
)
publicvoidrunWater(Stringvehicle){
System.out.printin(vehicle+”在水中運(yùn)行...;
}
j
2.3.3注意事項(xiàng)和細(xì)節(jié)
(1)降低類的復(fù)雜度,一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé)。
(2)提高類的可讀性,可維護(hù)性
(3)降低變更一個(gè)職責(zé)引起的風(fēng)險(xiǎn)
(4)通常情況下,我們應(yīng)當(dāng)遵守單一職責(zé)原則,只有邏輯足夠簡(jiǎn)單,才可以在代碼級(jí)違反
單一職責(zé)原則:只有類中方法數(shù)量足夠少,可以在方法級(jí)別保持單一職責(zé)原則。(如匕例)
2.4接口隔離原則(InterfaceSegregationPrinciple)
2.4.1基本介紹
客戶端不應(yīng)該依賴它不需要的接口,即一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接
口上。
先看一張圖:
(1)類A通過(guò)接口Interface1依賴類B,類C通過(guò)接口Interface1依賴類D,如果接口
Interface1對(duì)于類A和類C來(lái)說(shuō)不是最小接口,那么類B和類【)必須去實(shí)現(xiàn)他們不需要的
方法。(B、D的空心箭頭代表實(shí)現(xiàn),B和D都實(shí)現(xiàn)「Interfacel,這樣它們就得實(shí)現(xiàn)
Inter「小?(、1中的所有方法)(本圖就違反了接口隔離原則)
(2)按隔離原則應(yīng)當(dāng)這樣處理:將接口Interfacel拆分為獨(dú)立的幾個(gè)接口(這里我們拆
分成3個(gè)接口),類A和類C分別與他們需要的接口建立依賴關(guān)系,也就是采用接口隔
離原則。
2.4.2應(yīng)用實(shí)例
類A通過(guò)接口Interfacel依賴類B,類C通過(guò)接口Interfacel依賴類D,請(qǐng)編
寫代碼完成此應(yīng)用實(shí)例。
畫(huà)類圖:new->other->AmaterasUML(插件)->ClassDiagram
(1)沒(méi)有使用接口隔離原則的代碼
packagecom.principle.Segregation;
publicclassSegregation1{
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
}
)
〃接口
interfaceInterfacel{
voidoperation1();
voidoperation2();
voidoperation3();
voidoperation4();
voidoperations();
)
classBimplementsInterfacel{
’/需要加上public:因?yàn)椴荒芸s小其訪問(wèn)范圍
publicvoidoperationl(){
System.out.printIn(^B實(shí)現(xiàn)了operationl*);
)
publicvoidoperation20{
System.out.printIn(*B實(shí)現(xiàn)了operation?");
)
publicvoidoperations(){
System,out.printin(*B實(shí)現(xiàn)了operations*);
)
publicvoidoperation4(){
System.out.println(*B實(shí)現(xiàn)了operation/);
)
publicvoidoperations(){
System.out.printIn(^B實(shí)現(xiàn)了operations*);
)
)
classDimplementsInterfacel{
publicvoidoperationl(){
System.out.println(,,D實(shí)現(xiàn)了operationl^);
}
publicvoidoperation2(){
System.out.println(*D實(shí)現(xiàn)了operation?");
)
publicvoidoperations(){
System.out.printin("D實(shí)現(xiàn)了operations*);
}
publicvoidoperation4(){
System.out.printin(*D實(shí)現(xiàn)了operation/);
}
publicvoidoperations(){
System.out.println(z,D實(shí)現(xiàn)了operations*);
)
)
classA{
〃A類通過(guò)Interface1依賴(使用)B類,但是只會(huì)要到方法1,2,3
publicvoiddependl(Interfaceli){i.operationl();}
publicvoiddepend2(Interfaceli){i.operation2();}
publicvoiddepend3(Interfaceli)(i.operation3();}
)
classC{
〃C類通過(guò)Inlerfacel依賴(使用)D類,但是只會(huì)要到方法1,4,5
publicvoiddependl(Interfaceli){i.operationl();)
publicvoiddepend4(Interfaceli){i.operation4();}
publicvoiddepends(Interfaceli){i.operation5();)
)
(2)使用接口隔離原則改進(jìn)
1)問(wèn)題:類A通過(guò)接口Interfacel依賴類B,類C通過(guò)接口Interfacel依賴類
D,如果接口interfacel對(duì)于類A和類C來(lái)說(shuō)不是最小接口,那么類B和類D必須去
實(shí)現(xiàn)他們不需要的方法,造成了浪費(fèi)。
2)將接口Interfacel拆分為獨(dú)立的幾個(gè)接口,類A和類C分別與他們需要的接口建
立依賴關(guān)系,也就是采用接口隔離原則。
3)接口Interfacel中出現(xiàn)的方法,根據(jù)實(shí)際情況拆分為三個(gè)接口
OInterfacel
OB
。operationlO:void
O!nterface2
?opera60n20:void
?operation30:void
OInterfaces
。operation40:void
?operation50:void
4)代碼實(shí)現(xiàn)
publicclassSegregation1Tmprove(
publicstaticvoidmain(String1]args){
〃使用
Aa=newA();
//A類通過(guò)接口去依賴B類
a.dependl(newB());
a.depend2(newB());
a.depend3(newB());
Cc=newC0;
c.depend1(newD());
c.depend4(newDO);
c.depend5(newD());
}
)
〃接口1
interfaceInterfacel(
voidoperation1();
)
interfaceInterface2(
voidoperation2();
voidoperations();
)
interfaceInterfaces(
voidoperation4();
voidoperations();
)
classBimplementsInterfacel,Interface2{
〃需要加上public:因?yàn)椴荒芸s小其訪問(wèn)范圍
publicvoidoperationl(){
System,out.printin("B實(shí)現(xiàn)了operationTO;
}
publicvoidoperation2(){
System.out.printIn("B實(shí)現(xiàn)了operation2z/);
)
publicvoidoperations(){
System.out.printin("B實(shí)現(xiàn)了operations^);
}
)
classDimplementsInterfacel,Interfaces{
publicvoidoperationl(){
System.out.printin(,ZD實(shí)現(xiàn)了operationl*);
)
publicvoidoperation4(){
System,out.printin(Z,D實(shí)現(xiàn)了operation/);
)
publicvoidoperations(){
System.out.printin(*D實(shí)現(xiàn)了operations*);
)
classA{
〃A類通過(guò)Interface】,Interface2依賴(使用)B類,用到方法1,2,3
publicvoiddependl(Interfaceli){
i.operation1();
}
publicvoiddepend2(Interface2i)(
i.operation2();
)
publicvoiddepends(Interface2i){
i.operations();
)
)
classC{
〃C類通過(guò)Interfacol,Interface?依賴(使用)D類,用到方法1,4,5
publicvoiddependl(Interfaceli){
i.operation1();
}
publicvoiddepend4(Interfacesi)(
i.operation4();
)
publicvoiddepend5(lnterface3i){
i.operations();
}
)
2.5依賴倒轉(zhuǎn)原則
2.5.1基本介紹
依賴倒轉(zhuǎn)原則(DependenceInversionPrinciple)是指:
(1)高層模塊不應(yīng)該依賴低層模塊,二者都應(yīng)該依賴其抽象(抽象類/接口),不要去依
賴一個(gè)具體的子類
(2)抽象不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴抽象(這樣穩(wěn)定性會(huì)比較好)
(3)依賴倒轉(zhuǎn)(倒置)的中心思想是面向接口編程
(4)依賴倒轉(zhuǎn)原則是基于這樣的設(shè)計(jì)理念:相對(duì)于細(xì)節(jié)的多變性,抽象的東西要穩(wěn)定
的多。以抽象為基礎(chǔ)搭建的架構(gòu)比以細(xì)節(jié)為基礎(chǔ)的架構(gòu)要穩(wěn)定的多。在java
中,抽象指的是接口或抽象類,細(xì)節(jié)就是具體的實(shí)現(xiàn)類
(5)使用接口或抽象類的目的是制定好規(guī)范,而不涉及任何具體的操作,把展現(xiàn)細(xì)節(jié)
的任務(wù)交給他們的實(shí)現(xiàn)類去完成(接口和抽象類的HI)
2.5.2應(yīng)用實(shí)例
編程完成Person接收消息的功能。
(1)傳統(tǒng)方式
packagecom.principle,inversion;
publicclassDependecyInversion1{
publicstaticvoidmain(String口args){
Personperson=newPerson();
person,receive(newEmai10);
)
}
classEmai1{
publicStringgetlnfoO{
return”電子郵件信息:helloworld";
}
)
〃方式一分析
〃1.優(yōu)點(diǎn):簡(jiǎn)單,容易想到,容易實(shí)現(xiàn)
〃2.缺點(diǎn):如果我們獲取的對(duì)象是微信、短信等等,則需要新增類,同時(shí)Person也需
要增加相應(yīng)的接收方法(擴(kuò)展性不好)
〃3.解決思路:引入一個(gè)抽象的接口【Receiver,表示接收者,這樣Person類與接口
IReceiver發(fā)生依賴
//因?yàn)镋mail,WeiXin等等都屬于接收的范疇,它們各自實(shí)現(xiàn)【Receiver接口就
可以了,這樣就符合了依賴倒轉(zhuǎn)原則
classPerson{
publicvoidreceive(Emai1emai1){
System,out.printin(email,getlnfo());
}
)
(2)改進(jìn)方式
packagecom.principle,inversion;
publicclassDependecylnversionlImprove(
publicstaticvoidmain(String[]args){
〃客戶端無(wú)需改變
Personperson=newPerson();
person.receive(newEmai1());
person,receive(newWeChat());
)
}
interfaceIReceiver{
publicStringgetlnfoO;
)
classEmailimplementsIReceiver{
publicStringgetlnfoO{
return”電子郵件信息:helloworld*;
}
}
classWeChatimplementsIReceiver{
publicStringgetlnfoO{
return微信消息:hollo";
}
)
classPerson{
publicvoidreceive(IReceiverreceiver){
System,out.printIn(receiver.getlnfoO);
}
)
2.5.3依賴關(guān)系傳遞的三種方式
(1)接口傳遞
publicclassDependencyPass{
publicstaticvoidmain(String[]args){
ChangHongchangHong二newChangHong();
OpenAndCloseopenAndClose=newOpenAndClose();
openAndClose.open(changHong);
)
)
//方式1:通過(guò)接口傳遞實(shí)現(xiàn)依賴
//開(kāi)關(guān)的接口
interfaceIOpenAndClose{
publicvoidopen(ITVtv);//抽象方法,接收接口
)
interfaceITV{〃1TV接口
publicvoidplay0;
)
classChangHongimplementsITV{
?Override
publicvoidplay(){
System.out.printIn("長(zhǎng)虹電視機(jī),打開(kāi)");
}
)
//實(shí)現(xiàn)接口
classOpenAndCloseimplementsWpenAndClose{
publicvoidopen(ITVtv){
tv.play();
}
)
(2)構(gòu)造方法傳遞
publicclassDependencyPass{
publicstaticvoidmain(String口args){
ChangHongchangHong=newChangHong();
〃通過(guò)構(gòu)造器進(jìn)行依賴傳遞
OpenAndCloseopenAndClose=newOpenAndClose(changHong);
openAndClose.open();
)
)
〃方式2:通過(guò)構(gòu)造方法依賴傳遞
interfaceIOpenAndClose{
publicvoidopen();//抽象方法
}
interfaceITV{〃ITV接口
publicvoidplay();
)
classOpenAndCloseimplementsIOpenAndClose{
publicITVtv;//成員
publicOpenAndClose(ITVtv){//通過(guò)構(gòu)造器將接口傳入
this,tv=tv;
}
publicvoidopenO{this.tv.playO;}
)
classChangHongimplementsITV{
@Override
publicvoidplayO{
System.out.printIn("長(zhǎng)虹電視機(jī),打開(kāi)”);
}
)
(3)setter方式傳遞
publicclassDependencyPass{
publicstaticvoidmain(String口args){
ChangHongchangHong-newChangHong();
〃通過(guò)setter方法進(jìn)行依賴傳遞
OpenAndCloseopenAndClose=newOpenAndClose();
openAndClose.setTv(changHong);
openAndClose.open();〃沒(méi)有setTv()直接open0就會(huì)報(bào)空指針異常
}
)
〃方式3,通過(guò)setter方法傳遞
interfaceIOpenAndClose{
publicvoidopen();//抽象方法
publicvoidsetTv(ITVtv);
)
interfaceITV{//ITV接口
publicvoidplay();
)
classOpenAndCloseimplementsIOpenAndClose{
privateITVtv;
publicvoidsetTv(ITVtv){this,tv=tv;}
publicvoidopen(){this.tv.play();}
)
classChangHongimplementsITV{
?Override
publicvoidplay(){
System.printin'長(zhǎng)虹電視機(jī),打開(kāi)");
}
)
2.5.4注意事項(xiàng)和細(xì)節(jié)
(1)低層模塊盡量都要有抽象類或接口,或者兩者都有,程序穩(wěn)定性更好.
(2)變量的聲明類型盡量是抽象類或接口,這樣我們的變量引用和實(shí)際對(duì)象間,就存在一
個(gè)緩沖層,利于程序擴(kuò)展和優(yōu)化
比如:classAextendsB{),其中B是一個(gè)抽象類/接口,在使用時(shí):Bobj=new
A(),如果A類要進(jìn)行擴(kuò)展,只需要在B中增加一個(gè)方法即可。
(3)繼承時(shí)遵循里氏替換原則
2.6里式替換原則
2.6.100中的繼承性的思考和說(shuō)明
(1)繼承包含這樣一層含義:父類中凡是已經(jīng)實(shí)現(xiàn)好的方法,實(shí)際上是在設(shè)定規(guī)范和契
約,雖然它不強(qiáng)制要求所有的子類必須遵循這些契約,但是如果子類對(duì)這些已經(jīng)實(shí)現(xiàn)的方
法任意修改,就會(huì)對(duì)整個(gè)繼承體系造成破壞。
(2)繼承在給程序設(shè)計(jì)帶來(lái)便利的同時(shí),也帶來(lái)了弊端。比如使用繼承會(huì)給程序帶來(lái)侵入
性,程序的可移植性降低,增加對(duì)象間的耦合性,如果一個(gè)類被其他的類所繼承,則當(dāng)這
個(gè)類需要修改時(shí),必須考慮到所有的子類,并且父類修改后,所有涉及到子類的功能都有
可能產(chǎn)生故障
(3)問(wèn)題提出:在編程中,如何正確的使用繼承?=>盡量遵守里氏替換原則
2.6.2基本介紹
(1)里氏替換原則(LiskovSubstitutionPrinciple)在1988年,由麻省理工學(xué)院的以
為姓里的女士提出的。
(2)如果對(duì)每個(gè)類型為T1的對(duì)象。1,都有類型為T2的對(duì)象。2,使得以T1定義的所
有程序P在所有的對(duì)象ol都代換成o2時(shí),程序P的行為沒(méi)有發(fā)生變化(理想化原
則),那么類型T2是類型T1的子類型。換句話說(shuō),所有引用基類的地方必須能透明地使
用其子類的對(duì)象。
(3)在使用繼承時(shí),遵循里氏替換原則,在子類中盡量不要重寫父類的方法
(4)里氏替換原則告訴我們,繼承實(shí)際上讓兩個(gè)類耦合性增強(qiáng)了,在適當(dāng)?shù)那闆r下,可以
通過(guò)聚合,組合,依賴來(lái)解決問(wèn)題。(或者把原來(lái)的子類提升到與它的父類同一個(gè)層次,
做一個(gè)更加基礎(chǔ)的類,讓原來(lái)的子類和父類來(lái)繼承,以此來(lái)降低原子類和父類的耦合性)
2.6.3一個(gè)程序引出的問(wèn)題和思考
(1)問(wèn)題
看如下程序,思考問(wèn)題和解決思路:
classA{publicstaticvoidmain(String[]args){
publicintfunclfintnuml,intnum2){Aa=newA();
returnnuml-num2;System.out.println("ll-3="+a.funcl(ll,3));
}}System.out.println("l-8="?a.funcl(l,8));
System.out.println("------------------------");
classBextendsA{Bb=newB();
publicintfuncl(lnta,intb){System.out.println("ll-3="?b.funclfll,3));
returna+b;}System.out.println("l"8="b.fund(l,8));
publicintfunc2(inta,intb){System.out.println("ll+3+9=M+b.func2(ll,3));
returnfund(a,b)+9;)
)}
publicclassLiskov{
publicstaticvoidmain(String[]args){
Aa=newA();
System,out.printing11-3="+a.fund(11,3));//8
System.out.printIn(*l-8="z+a.fund(1,8))://-7
System,out.printin--------二〃);
Bb=newB0;
System,out.println(^ll-3=*+b.fund(11,3));〃這里本意是求出11-
3,實(shí)際求的是11+3
System,out.println(*l-8=z,+b.fund(1,8));//9
System,out.printIn(^11+3+9=*+b.func2(l1,3));
}
)
//A類
classA{
〃返回兩個(gè)數(shù)的差
publicintfund(intnuml,intnum2){
returnnuml-num2:
}
)
//B類繼承了A
〃增加了一個(gè)新功能:完成兩個(gè)數(shù)相加,然后和9求和
classBextendsA{
〃這里,重寫了A類的方法,可能是無(wú)意識(shí)的
publicintfund(inta,intb){
returna+b;
)
publicintfunc2(inta,intb){
returnfund(a,b)+9;
(2)解決方法
1)我們發(fā)現(xiàn)原來(lái)運(yùn)行正常的相減功能發(fā)生了錯(cuò)誤。原因就是類B無(wú)意中重寫了父類
的方法,造成原有功能出現(xiàn)錯(cuò)誤。在實(shí)際編程中,我們常常會(huì)通過(guò)重寫父類的方法完成新
的功能,這樣寫起來(lái)雖然簡(jiǎn)單,但整個(gè)繼承體系的復(fù)用性會(huì)比較差。特別是運(yùn)行多態(tài)比較
頻繁的時(shí)候
2)通用的做法是:原來(lái)的父類和子類都繼承一個(gè)更通俗(更基本)的基類,將原有的繼
承關(guān)系去掉,采用依賴,聚合,組合等關(guān)系代替.
(3)改進(jìn)方案
(如果B類要用至IJA類,可以采用依賴、聚合、組合的方式,如圖中
的畫(huà)法是組合)
packagecom.principle.1iskov;
publicclassLiskovlmprove{
publicstaticvoidmain(String[]args){
Aa=newA();
System.out.printIn(,z11-3=*+a.fund(11,3));//8
System,out.printIn(^1-8=^+a.fund(1,8));//-7
System,out.print1n(*================z>);
Bb=newB();
〃因?yàn)锽類不再繼承A類,因此,調(diào)用者就不會(huì)再認(rèn)為funclO是在求減法了
〃此時(shí),調(diào)用某個(gè)方法會(huì)完成的功能就很明確了
System,out.println(,zl1+3=*+b.fund(11,3));
System,out.println(*l+8=*+b.fund(1,8));//9
System.out.println(z,11+3+9=*+b.func2(l1,3));
〃使用組合仍然可以使用到A的相關(guān)方法
System.out.printIn(*11-3=*+b.func3(ll,3));
}
)
〃創(chuàng)建?個(gè)更加基礎(chǔ)的基類
classBase(
〃把更加基礎(chǔ)的方法和成員寫到Base類中
)
//A類
classAextendsBase(
〃返回兩個(gè)數(shù)的差
publicintfund(intnuml,intnum2){
returnnuml-num2;
)
)
〃8不再繼承A類,降低了A和B之間的耦合度
classBextendsBase{
〃如果B類需要使用A類的方法,此處選擇使用組合關(guān)系
privateAa=newA();
〃使用A的方法
publicintfunc3(inta,intb){
returnthis.a.fund(a,b);
}
publicintfund(inta,intb){returna+b;)
publicintfunc2(inta,intb){returnfund(a,b)+9;)
}
2.7開(kāi)閉原則
2.7.1基本介紹
(1)開(kāi)閉原則(OpenClosedPrinciple)是編程中最基礎(chǔ)、最重要的設(shè)計(jì)原則(核心)
(2)?個(gè)軟件實(shí)體如類,模塊和函數(shù)應(yīng)該對(duì)擴(kuò)展開(kāi)放(指對(duì)提供方開(kāi)放),對(duì)修改關(guān)閉(指
對(duì)使用方關(guān)閉)。用抽象構(gòu)建框架,用實(shí)現(xiàn)擴(kuò)展細(xì)節(jié)。
(3)當(dāng)軟件需要變化時(shí),盡量通過(guò)擴(kuò)展軟件實(shí)體的行為來(lái)實(shí)現(xiàn)變化,而不是通過(guò)修改已有
的代碼來(lái)實(shí)現(xiàn)變化。(盡量增加一種功能/擴(kuò)展,而不是修改,因?yàn)楸恍薷牡倪@部分可能正
在被使用)
(4)編程中遵循其它原則,以及使用設(shè)計(jì)模式的目的就是遵循開(kāi)閉原則。
2.7.2應(yīng)用實(shí)例
(1)案例
看下面一段代碼,完成一個(gè)畫(huà)圖形的功能,類圖設(shè)計(jì)如下:
packagecom.principle.ocp;
publicclassOcp{
publicstaticvoidmain(String[]args){
〃使用看看存在的問(wèn)題
GraphicEditorgraphicEditor=newGraphicEditor();
graphicEditor.drawShape(newRectangle0);
graphicEditor.drawShape(newCircle());
graphicEditor.drawShape(newTriangleO);
)
)
〃這是一個(gè)用于繪圖的類[使用方]
classGraphicEditor{
〃接收Shape對(duì)象,然后根據(jù)type,來(lái)繪制不同的圖形
publicvoiddrawShape(Shapes){
if(s.m_type==l)
drawRectangle(s);
elseif(s.m_type==2)
drawCircle(s);
elseif(s.mtype==3)
drawTriangle(s);}
//繪制矩形
publicvoiddrawRectangle(Shaper){
System.out.println(*繪制矩形”);
)
〃繪制圓形
publicvoiddrciwCircle(Shaper){
System.out.printlnC*繪制圓形”);
}
//繪制三角形
publicvoiddrawTriangle(Shaper){
System.out.printin("繪制三角形”);
)
)
//Shape類,基類
classShape{
intm_type;
)
classRectangleextendsShape{
Rectangle(){
super.m_type=1;
)
)
classCircleextendsShape{
Circle(){
super.intype=2;
}
)
//新增畫(huà)三角形
classTriangleextendsShape{
Triangle(){
super,mtype=3;
)
}
方法一的優(yōu)缺點(diǎn)
1)優(yōu)點(diǎn)是比較好理解,簡(jiǎn)單易操作。
2)缺點(diǎn)是違反了設(shè)計(jì)模式的。cp原則,即對(duì)擴(kuò)展開(kāi)放(提供方),對(duì)修改關(guān)閉(使用
方)。即當(dāng)我們給類增加新功能的時(shí)候,盡量不修改代碼,或者盡可能少修改代碼.
3)比如我們要新增加一個(gè)圖形種類:三角形,需要修改的地方較多(使用方的代碼也被
修改了),代碼如上。
(2)改進(jìn)方案
改進(jìn)的思路分析
把Shape類做成抽象類,并提供一個(gè)抽象的draw方法,讓子類去實(shí)現(xiàn)即可,這樣我
們有新的圖形種類時(shí),只需要讓新的圖形類繼承Shape,并實(shí)現(xiàn)draw方法即可,使用方
的代碼就不需要修改->滿足了開(kāi)閉原則
改進(jìn)后的代碼:
publicclassOcplmprove{
publicstaticvoidmain(String口args){
〃使用看看存在的問(wèn)題
GraphicEditorgraphicEditor=newGraphicEditor();
graphicEditor.drawShape(newRectangle0);
graphicEditor.drawShape(newCircleO);
graphicEditor.drawShape(newTriangleO);
graphicEditor.drawShape(newOther
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 甲供材料合同范本
- 幼兒園托管協(xié)議合同8篇
- 居間合同居間合同
- 2025年克拉瑪依c1貨運(yùn)從業(yè)資格證考試內(nèi)容
- 工程施工監(jiān)理合同
- 專項(xiàng)工程承包合同文本
- 建筑工程項(xiàng)目分包合同
- 增加附錄條款魚(yú)種購(gòu)銷合同
- 運(yùn)輸水合同范本
- 卷煙戰(zhàn)略市場(chǎng)規(guī)劃報(bào)告
- 《管理研究方法》教學(xué)大綱
- 2024年急危重癥患者鼻空腸營(yíng)養(yǎng)管管理專家共識(shí)
- 2024年機(jī)動(dòng)車駕駛員考試《科目一》試卷及解答參考
- 2024人工智能開(kāi)源大模型生態(tài)體系研究報(bào)告
- DL∕T 974-2018 帶電作業(yè)用工具庫(kù)房
- 《多元統(tǒng)計(jì)分析-基于R(第3版)》課件全套 費(fèi)宇 第1-13章-多元統(tǒng)計(jì)分析與R簡(jiǎn)介-多維標(biāo)度分析
- 現(xiàn)代家譜名人錄范文
- 質(zhì)譜儀產(chǎn)品商業(yè)計(jì)劃書(shū)
- 《設(shè)計(jì)手抄報(bào)》教學(xué)教案設(shè)計(jì)
- 基金應(yīng)知應(yīng)會(huì)專項(xiàng)考試題庫(kù)(證券類190題)附有答案
- 陜西省2024年高中學(xué)業(yè)水平合格考數(shù)學(xué)試卷試題(含答案)
評(píng)論
0/150
提交評(píng)論