設(shè)計模式訪問者模式_第1頁
設(shè)計模式訪問者模式_第2頁
設(shè)計模式訪問者模式_第3頁
設(shè)計模式訪問者模式_第4頁
設(shè)計模式訪問者模式_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第九章訪問者模式九.一問題地提出九.二訪問者模式九.三深入理解訪問者模式九.四應(yīng)用示例九.一問題地提出我們知道,們認識事物常常有一個循序漸地過程,不可能是一蹴而就地。例如某事物經(jīng)分析后有功能一,功能二,但是或者隨著時間地推移,或者隨著需求分析地變化,或者隨著二次開發(fā)地需要,我們還需要要完成功能三。這樣地特點,計算機如何能更好地描述呢?常規(guī)思路如下所示:原功能變化后功能interfaceIFunc{ voidfunc(); //功能一 voidfunc二(); //功能二 }classThingimplementsIFunc{ publicvoidfunc(){} publicvoidfunc二(){}}

interfaceIFunc{ voidfunc(); //功能一 voidfunc二(); //功能二 voidfunc三(); //功能三}classThingimplementsIFunc{ publicvoidfunc(){} publicvoidfunc二(){} publicvoidfunc三(){}}可知新增功能三主要是通過在IFunc接口增加方法定義func三(),再在實現(xiàn)類Thing重寫func三()方法完成地。這種方法是常規(guī)思路,最大特點是若增加新功能,需要修改接口及相應(yīng)實現(xiàn)。那么,能不能不修改IFunc,Thing,也能實現(xiàn)新增地功能三呢?訪問者模式是具體實現(xiàn)地手段之一。一.抽象類圖九.二訪問者模式圖九-一訪問者模式抽象類圖<<interface>>IElement+//固定功能定義+accept(visit:IVisitor):Object+visit(element:ElementA)+visit(element:ElementB)<<interface>>IVisitorElementAElementBVisitor一Visitor二

Clientusesuses二.類圖說明?IElement:抽象地事物元素功能接口,定義了固定功能方法及可變功能方法接口。?Element:具體功能地實現(xiàn)類。?IVisitor:訪問者接口,為所有訪問者對象聲明一個visit方法,用來代表為對象結(jié)構(gòu)添加地功能,原則上可以代表任意地功能。?Visitor:具體訪問者實現(xiàn)類,實現(xiàn)要真正被添加到對象結(jié)構(gòu)地功能。考慮這樣一個應(yīng)用:已知三點坐標,編寫功能類,求所圍三角形地面積與周長。如果采用訪問者模式架構(gòu),應(yīng)當這樣思考:目前已確定地需求分析是求面積與周長功能,但有可能將來求三角形地重心,垂心坐標,內(nèi)切,外界圓地半徑等,因此,在設(shè)計時需要考慮如何屏蔽這些不確定情況。具體代碼如下所示。一.定義抽象需求分析接口IShapeinterfaceIShape{ floatgetArea(); //明確地需求分析 floatgetLength(); //明確地需求分析 Objectaccept(IVisitorv); //可擴展地需求分析}二.定義具體功能實現(xiàn)類TriangleclassTriangleimplementsIShape{ floatx一,y一,x二,y二,x三,y三; //三角形三點坐標 publicTriangle(floatx一,floaty一,floatx二,floaty二,floatx三,floaty三){

this.x一=x一;this.y一=y一; this.x二=x二;this.y二=y二; this.x三=x三;this.y三=y三; } publicfloatgetDist(floatu一,floatv一,floatu二,floatv二){ //求任意兩點距離 return(float)Math.sqrt((u一-u二)*(u一-u二)+(v一-v二)*(v一-v二)); } publicfloatgetArea(){ //固定需求分析求面積 floata=getDist(x一,y一,x二,y二); floatb=getDist(x一,y一,x三,y三); floatc=getDist(x二,y二,x三,y三); floats=(a+b+lc)/二; return(float)Math.sqrt(s*(s-a)*(s-b)*(s-c));//海倫公式求面積 } publicfloatgetLength(){ //固定需求分析求周長 floata=getDist(x一,y一,x二,y二); floatb=getDist(x一,y一,x三,y三); floatc=getDist(x二,y二,x三,y三); returna+b+c; } publicObjectaccept(IVisitorv){ //可擴展需求分析 returnv.visit(this); }}著重理解accept()方法,可知IVisitor接口一定定義了多態(tài)方法visit(),那為什么把this引用傳過去呢?可以這樣理解:例如若求三角形重心坐標,它地功能一定是在IVisitor地子類實現(xiàn)地,那么該子類一定得知道三角形地三個坐標,因此把this應(yīng)用傳過去,相當于IVisitor地子類可訪問Triangle類地成員變量,編制求重心坐標就容易了。三.定義訪問者接口IVisitorinterfaceIVisitor{ Objectvisit(Trianglet);}四.定義重心坐標實現(xiàn)類CenterVisitorclassPoint{ floatx,y;}classCenterVisitorimplementsIVisitor{ publicObjectvisit(Trianglet){ Pointpt=newPoint(); pt.x=(t.x一+t.x二+t.x三)/三; pt.y=(t.y一+t.y二+t.y三)/三; returnpt; }}一個簡單地測試類如下所示。publicclassTest三{ publicstaticvoidmain(String[]args){ IVisitorv=newCenterVisitor(); //定義求重心具體訪問者對象 Trianglet=newTriangle(零,零,二,零,零,二); //定義三角形對象 Pointpt=(Point)t.accept(v); //通過訪問者對象求三角形重心坐標 System.out.println(pt.x+"\t"+pt.y); }}九.三深入理解訪問者模式一.應(yīng)用反射技術(shù)現(xiàn)在三角形需要新增計算重心坐標,及求三角形內(nèi)切圓半徑功能,具體代碼如下所示。(一).定義抽象需求分析接口IShapeinterfaceIShape{ floatgetArea(); floatgetLength(); Objectaccept(IVisitorv,Stringmethod);}(二).定義具體功能實現(xiàn)類TriangleclassTriangleimplementsIShape{ //其余代碼同九.二 publicObjectaccept(IVisitorvisit,Stringmethod){ returnvisit.visit(this,method); }}(三)定義訪問者接口IVisitorinterfaceIVisitor{ Objectvisit(Trianglet,Stringmethod);}(四)具體實現(xiàn)訪問者類ShapeVisitorclassPoint{/*同九.二*/}classShapeVisitorimplementsIVisitor{ publicObjectgetCenter(Trianglet){//獲取重心坐標 Pointpt=newPoint(); pt.x=(t.x一+t.x二+t.x三)/三; pt.y=(t.y一+t.y二+t.y三)/三; returnpt; } publicFloatgetInnerCircleR(Trianglet){//獲取內(nèi)切圓半徑 floatarea=t.getArea(); floatlen=t.getLength(); returnnewFloat(二.零f*area/len); } publicObjectvisit(Trianglet,Stringmethod){//訪問者接口轉(zhuǎn)發(fā)方法 Objectresult=null; try{ Classclassinfo=this.getClass(); Methodmt=classinfo.getMethod(method,Triangle.class); result=mt.invoke(this,newObject[]{t}); } catch(Exceptione){} returnresult; }}一個測試類如下所示。publicclassTest四{ publicstaticvoidmain(String[]args)throwsException{ IVisitorv=newShapeVisitor(); //定義訪問者 Trianglet=newTriangle(零,零,二,零,零,二); //定義具體事物元素類 Pointpt=(Point)t.accept(v,"getCenter");//獲得重心坐標 System.out.println("重心坐標x="+pt.x+"\ty="+pt.y); Floatf=(Float)t.accept(v,"getInnerCircleR"); //獲得內(nèi)切圓半徑 System.out.println("內(nèi)切圓半徑r="+f.floatValue()); }}二.抽象訪問者定義形式已知某元素有兩種類型,定義訪問者基本模式框架。代碼簡述如下所示。(一)定義抽象事物IElementinterfaceIElement{publicvoidaccept(IVisitorv); //與訪問者接口方法}

(二)定義兩個具體事物Element,Element二classElementimplementsIElement{ publicvoidaccept(IVisitorv){ v.visit(this); } }classElement二implementsIElement{ publicvoidaccept(IVisitorv){ v.visit(this); } }(三)定義抽象訪問者及具體實現(xiàn)類方法一:仔細分析Element,Element二兩個類地accept()方法,有一行重要地語句v.visit(this),this代表Element(或Element二)對象。因此,抽象訪問者定義成如下形式。interfaceIVisitor{ publicvoidvisit(Elementobj); publicvoidvisit(Element二obj);}也就是說,如果IElement有N個子類,抽象訪問者接口就要定義N個方法。具體訪問者直接實現(xiàn)該抽象接口即可。方法二:雖然上文v.visit(this)代碼this代表Element(或Element二)對象,但它們都是IElement地子類對象。因此,抽象訪問者定義成如下形式。interfaceIVisitor{ publicvoidvisit(IElementobj);} 也就是說,不論IElement多少個子類,抽象訪問者接口僅定義一個方法。那么,在哪里判斷IElement引用是哪個具體地子類對象呢?當然在訪問者具體實現(xiàn)子類,一個示例代碼如下所示。classOneVisitorimplementsIVisitor{ publicvoidvisit(IElementobj){ if(objinstanceofElement) {/*處理代碼*/} else {/*處理代碼*/} }}三.構(gòu)建集合對象自適應(yīng)功能框架自適應(yīng)功能框架地意義是當需求分析發(fā)生變化后,僅添加相應(yīng)地具體功能,而程序地主框架不變。我們知道,集合是由元素組成地,集合與元素是相對地,例如:A是B地集合,B是C地集合,一般來說,只有A,B,C均是自適應(yīng)地,整個系統(tǒng)才能稱為功能框架。訪問者模式是實現(xiàn)集合對象自適應(yīng)功能框架地重要手段??紤]一個存折管理系統(tǒng):假設(shè)僅在工商銀行與農(nóng)業(yè)銀行存定期存折,編制相應(yīng)地自適應(yīng)程序管理框架。①定義泛型訪問者接口IVisitorinterfaceIVisitor<T>{ voidvisit(Ts);}②定義存單有關(guān)類//存單抽象基類SheetabstractclassSheet{ Stringaccount; //帳號 Stringname; //姓名 floatmoney; //余額 StringstartDate; //存款日期 intrange; //期限 publicSheet(Stringaccount,Stringname,floatmoney,StringstartDate,intrange){ this.account=account;=name;this.money=money; this.startDate=startDate;this.range=range; } publicvoidaccept(IVisitor<Sheet>v){ v.visit(this); }}//工行存單子類ICBCSheet,農(nóng)行存單子類ABCSheetclassABCSheetextendsSheet{ //農(nóng)行存單類 publicABCSheet(Stringaccount,Stringname,floatmoney,StringstartDate,intrange){ super(account,name,money,startDate,range); }}classICBCSheetextendsSheet{ //工行存單類 publicICBCSheet(Stringaccount,Stringname,floatmoney,StringstartDate,intrange){ super(account,name,money,startDate,range); } }③各個銀行存單管理類abstractclassBank{ publicvoidaccept(IVisitor<Bank>v){ v.visit(this); } publicabstractvoidprocess(IVisitor<Sheet>visit);}//兩個銀行子類ABCBank,ICBCBankclassABCBankextendsBank{ Vector<ABCSheet>v=newVector(); voidadd(ABCSheets){ v.add(s); } publicvoidprocess(IVisitor<Sheet>visit){ for(inti=零;i<v.size();i++){ v.get(i).accept(visit); } }}classICBCBankextendsBank{ Vector<ICBCSheet>v=newVector(); voidadd(ICBCSheets){ v.add(s); } publicvoidprocess(IVisitor<Sheet>visit){ for(inti=零;i<v.size();i++){ v.get(i).accept(visit); } }}④銀行組存單管理類classBankGroup{ Vector<Bank>v=newVector(); voidadd(Bankbank){ v.add(bank); } publicvoidaccept(IVisitor<BankGroup>v){ v.visit(this); } publicvoidprocess(IVisitor<Bank>visit){ for(inti=零;i<v.size();i++){ v.get(i).accept(visit); } } }⑤簡單地測試類編制方法classSheetVisitorimplementsIVisitor<Sheet>{ privatevoidABCProc(ABCSheetsheet){ System.out.println("ABCSheetprocess"); } privatevoidICBCProc(ICBCSheetsheet){ System.out.println("ICBCSheetprocess"); } publicvoidvisit(Sheets){ if(sinstanceofABCSheet){ ABCProc((ABCSheet)s); } if(sinstanceofICBCSheet){ ICBCProc((ICBCSheet)s); } } }classBankVisitorimplementsIVisitor<Bank>{ privatevoidABCProc(ABCBankbank){ System.out.println("ABCBankprocess"); } privatevoidICBCProc(ICBCBankbank){ System.out.println("ICBCBankprocess"); } publicvoidvisit(Bankb){ if(binstanceofABCBank){ ABCProc((ABCBank)b); } if(binstanceofICBCBank){ ICBCProc((ICBCBank)b); } }}九.四應(yīng)用示例例九-一學生成績查詢功能文本文件示例說明班級:一年一班一零零一zhang七零八零九零一零零二zhang二七一八一九一一零零三zhang三六九七九八九一零零四zhang四六五八零九零班級:一年二班一零零五zhao七零八零九零一零零六zhao二七一八一九一均有前綴"班級",表示以下是該班成績一行一個學生紀錄,表示:學號,姓名,語文,數(shù)學,外語成績,間由單空格隔開。

又一個班地數(shù)據(jù)學生成績已經(jīng)保存在文本文件,格式如圖所示。一.學生成績信息獲得有關(guān)代碼//學生類StudentclassStudent{ StringstudNO;//學號 Stringname; //姓名 intchinese; //語文成績 intmath; //數(shù)學成績 intenglish; //外語成績 publicStudent(Stringt[]){ studNO=t[零];name=t[一]; chinese=Integer.parseInt(t[二]); math=Integer.parseInt(t[三]); english=Integer.parseInt(t[四]); }}//班級類BanjiinterfaceIVisitor{ voidvisit(Banjiobj,JPanelpanel);}classBanji{ Vector<Student>v=newVector(); //班級是學生地集合 publicVector<Student>getV(){ returnv; } voidadd(Students){ //班級增加學生 v.add(s); } voidstatistics(IVisitorv,JPanelpanel){ //訪問者接口方法 v.visit(this,panel); }}//年級類GradeclassGrade{ Map<String,Banji>map=newHashMap(); //key:班級名稱 publicBanjiadd(Stringbanji){ Banjiobj=newBanji(); map.put(banji,obj); returnobj; } publicvoidreadFile(StringstrFile){ //讀學生成績信息文件 Strings=""; Banjiobj=null; try{ FileReaderin=newFileReader(strFile); BufferedReaderin二=newBufferedReader(in); while((s=in二.readLine())!=null){ s=s.trim(); if(s.equals(""))continue; if(s.startsWith("班級")){ obj=add(s); continue; } Stringt[]=s.split(""); Studentstud=newStudent(t); obj.add(stud); }

in二.close(); in.close(); } catch(Exceptione){e.printStackTrace();}}二.界面生成有關(guān)代碼classMyFrameextendsJFrame{ Gradegrade=newGrade(); //定義年級成員變量 JPanelcontentPane=newJPanel(); //定義主界面右側(cè)內(nèi)容面板 JboBoxbo; //主界面選擇班級下拉框?qū)ο?/p>

ActionListenera一=newActionListener(){ //"成績顯示"按鈕響應(yīng)方法 publicvoidactionPerformed(ActionEvente){ Stringfactor=(String)bo.getSelectedItem(); Banjiobj=(Banji)grade.map.get(factor); Vector<Student>v=obj.getV(); Stringtitle[]={"學號","姓名","語文","數(shù)學","英語"}; Stringd[][]=newString[v.size()][五]; for(inti=零;i<v.size();i++){ Studentunit=v.get(i); d[i][零]=unit.studNO;d[i][一]=;d[i][二]=""+unit.chinese; d[i][三]=""+unit.math;d[i][四]=""+unit.english; } showTable(d,title); } }; ActionListenera二=newActionListener(){ //"統(tǒng)計功能"按鈕響應(yīng)方法 publicvoidactionPerformed(ActionEvente){ Stringfactor=(String)bo.getSelectedItem(); Banjiobj=(Banji)grade.map.get(factor); Vector<Student>v=obj.getV(); obj.statistics(newStaVisitor(),contentPane); } }; publicvoidshowTable(Stringd[][],Stringtitle[]){ contentPane.removeAll(); contentPane.setLayout(newBorderLayout()); JTabletab=newJTable(d,title); JScrollPanescr=newJScrollPane(tab); contentPane.add(scr); contentPane.updateUI(); } publicvoidinit(StringstrFile){ grade.readFile(strFile); //讀數(shù)據(jù)文件,形成數(shù)據(jù)集合 setLayout(null); //布局管理器設(shè)置為空 Set<String>set=grade.map.keySet(); Objectinfo[]=set.toArray(); bo=newJboBox(info); //填充班級下拉框內(nèi)容 bo.setBounds(一零,一零,一五零,三零); add(bo); //將班級下拉框添加到界面

JButtondispBtn=newJButton("成績顯示"); JButtoninfoBtn=newJButton("統(tǒng)計功能"); dispBtn.addActionListener(a一); //注冊"成績顯示"消息 infoBtn.addActionListener(a二); //注冊"統(tǒng)計功能"消息 dispBtn.setBounds(一零,六零,一五零,三零);

溫馨提示

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

評論

0/150

提交評論