模式與框架-Java EE設(shè)計(jì)與開發(fā).doc_第1頁
模式與框架-Java EE設(shè)計(jì)與開發(fā).doc_第2頁
模式與框架-Java EE設(shè)計(jì)與開發(fā).doc_第3頁
模式與框架-Java EE設(shè)計(jì)與開發(fā).doc_第4頁
模式與框架-Java EE設(shè)計(jì)與開發(fā).doc_第5頁
已閱讀5頁,還剩73頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第1頁,共78頁 模式與框架模式與框架 javajava eeee設(shè)計(jì)與開發(fā)設(shè)計(jì)與開發(fā) 第2頁,共78頁 目錄 第第1章章 模式與框架介模式與框架介紹紹2 1.1 什么是模式. 2 1.2 什么是框架. 3 1.3 模式與框架的區(qū)別.3 1.4 架構(gòu)模式. 3 1.5 java ee核心模式.4 1.6 gof模式. 6 第第2章章 數(shù)據(jù)數(shù)據(jù)層層框架與模式框架與模式7 2.1 示例. 7 2.2 使用模式. 9 2.3 使用設(shè)計(jì)原則.16 2.4 數(shù)據(jù)層框架.21 2.5 調(diào)用. 29 第第3章章 業(yè)務(wù)層業(yè)務(wù)層框架與模式框架與模式30 第第4章章 表表現(xiàn)層現(xiàn)層框架與模式框架與模式30 第第5章章 mvc框架與框架與應(yīng)應(yīng)用用31 第3頁,共78頁 第第1章章 模式與框架介紹模式與框架介紹 1.1 1.1 什么是模式什么是模式 模式就是解決問題的方法論。每一種模式都描述了解決某一類問題的最佳方法,至少 到目前為止是。模式是理論與實(shí)踐相結(jié)合而總結(jié)出來的最有效的解決方案,它將隨著技 術(shù)的發(fā)展而不斷創(chuàng)新,不斷完善,所以舊的模式會(huì)發(fā)現(xiàn)不再適用,而新的模式會(huì)出現(xiàn)。 模式在各個(gè)應(yīng)用領(lǐng)域都有,譬如在建筑設(shè)計(jì)中,模式最為常見。如將門安裝在距離墻 角落 120 公分處,窗戶與欄桿的高度在 90 公分左右,長高寬為 300 的模數(shù)等。同理,軟 件設(shè)計(jì)中,模式也是層出不窮,大量的架構(gòu)模式,創(chuàng)建模式,結(jié)構(gòu)模式,行為模式,表 現(xiàn)層模式,業(yè)務(wù)層模式,數(shù)據(jù)層模式等等。 1.2 1.2 什么是框架什么是框架 就是一組組件、類或接口構(gòu)成的半成品,僅完成了某些基本功能,譬如日志,安全性, 數(shù)據(jù)訪問等,但需要在此基礎(chǔ)上進(jìn)行業(yè)務(wù)開發(fā),最終構(gòu)成一個(gè)可用的業(yè)務(wù)系統(tǒng)?;诳?架的開發(fā)可以節(jié)省大量的精力而致力于系統(tǒng)的業(yè)務(wù)邏輯設(shè)計(jì)。 譬如在建筑領(lǐng)域,屋架、梁柱就是一個(gè)典型的框架,是一個(gè)半成品。屋架的作用是 承重,但不能遮風(fēng)擋雨,必須在上面蓋瓦或鋪設(shè)覆蓋物,形成屋頂,才能具備完整的功 能;糧柱的其本作用是劃分空間、承受垂直與橫向的壓力,但不具備封閉空間、隔聲的 效果,尚待在柱間砌筑墻體,在梁間鋪設(shè)樓板才能居住。 在軟件開發(fā)中,框架僅提供了部分通用的功能,還必須經(jīng)過業(yè)務(wù)的填充,才能形成一 個(gè)功能齊全的業(yè)務(wù)系統(tǒng)。 1.3 1.3 模式與框架的區(qū)別模式與框架的區(qū)別 從規(guī)模上講,模式專注于微觀層面的分析與設(shè)計(jì),而框架著眼于宏觀的構(gòu)造。 從實(shí)現(xiàn)的角度看,模式只是一種解決問題的方法,一個(gè)解決方案,而框架卻是一個(gè)實(shí) 現(xiàn)這種方案的具體的產(chǎn)品,有著實(shí)際的功效與作用。 從關(guān)系上講,模式是框架的理論基礎(chǔ),多個(gè)模式的實(shí)現(xiàn)構(gòu)成了一個(gè)框架??蚣苁悄J?的具體實(shí)現(xiàn),一個(gè)局部或全局的框架,一般都要用到模式。 既然是框架,本身就表示它是一種好的通用的產(chǎn)品,怎么體現(xiàn)它是好的呢,模式恰好 證明了它是解決某一類問題的最好的解決方案,所以說,沒有用到模式的框架,將不是 一個(gè)良好的可用的框架。 1.4 1.4 架構(gòu)模式架構(gòu)模式 第4頁,共78頁 專注于體系結(jié)構(gòu)宏觀的組成與創(chuàng)建,而不注重其細(xì)節(jié)。譬如建筑設(shè)計(jì)中常用的體系結(jié) 構(gòu)模式有:低層建筑采用磚混結(jié)構(gòu),中高層采用梁柱框架結(jié)構(gòu),高層建筑普遍采用鋼結(jié) 構(gòu)、剪力墻結(jié)構(gòu)、洐架結(jié)構(gòu)。 在軟件應(yīng)用領(lǐng)域,架構(gòu)模式也是豐富多用,主要有以下幾種: 層次模式:layers 管道和過濾模式:pipes and filters 代理模式: broker 黑板模式:blackboard 水平-垂直元素模式:horizontal-vertical metadata mvc 模式:主要針對(duì)系統(tǒng)或子系統(tǒng)和接口 1.5 1.5 javajava eeee核心模式核心模式 在 java web 應(yīng)用與企業(yè)應(yīng)用領(lǐng)域,常用的體系架構(gòu)是 mvc。而 mvc 正好體現(xiàn)了分 層的思想。各層之間的聯(lián)系與區(qū)別如下 圖: 表示層表示層 業(yè)務(wù)層業(yè)務(wù)層 model1 model2 mvc2 mvc 數(shù)據(jù)層數(shù)據(jù)層 m v c 我們一般將視圖(view)與控制器(controller)叫做表示層,而模型層太籠統(tǒng),在 實(shí)際中,我們將模型層分割為業(yè)務(wù)層與數(shù)據(jù)層。其中 v 或 v+m 構(gòu)成了我們的 model1 架構(gòu), v+c+m 構(gòu)成了 model2 架構(gòu),又叫 web mvc 或 mvc2 架構(gòu),因?yàn)椴恢С滞剖?。但我們?xí) 慣將其稱為 mvc 體系架構(gòu)。 sun java center 定義了 15 種設(shè)計(jì)模式,在core j2ee patterns書中發(fā)表。按照 mvc 的分層,在每一層都提出了幾種模式,這些模式分別組成各層,最后組成一個(gè)完整 第5頁,共78頁 的 mvc 框架。 這些模式分為: 表現(xiàn)層模式,又稱 web 層模式,用于 web 層的界面與 servlet 開發(fā); 業(yè)務(wù)層模式,又稱應(yīng)用層模式,用于業(yè)務(wù)邏輯的分層與調(diào)用; 數(shù)據(jù)層模式,又稱集成層模式,用于數(shù)據(jù)訪問 表現(xiàn)層模式表現(xiàn)層模式 intercepting filter(截獲過濾截獲過濾) 對(duì)請(qǐng)求和響應(yīng)進(jìn)行截獲和過濾,在 servlet2.3 中已實(shí)現(xiàn)的 filter 功能就是屬于此模式。 該模式可用于單點(diǎn)登陸,以及登陸過程驗(yàn)證等等。 front controller(前端控制器前端控制器) servlet 設(shè)計(jì)的思想主要是用來調(diào)度和轉(zhuǎn)發(fā)。即調(diào)用模型層的類來處理請(qǐng)求,然后將 處理后的信息轉(zhuǎn)發(fā)到響應(yīng)頁面進(jìn)行展示,絕不能將業(yè)務(wù)邏輯代碼堆砌在 servlet 方法中。 那么如何能體現(xiàn) servlet 的這一功能需求呢,前端控制器模式很好的解決了這個(gè)問題,在 一個(gè)項(xiàng)目中,只有一個(gè)控制器,它是系統(tǒng)的一個(gè)入口,由他調(diào)用相應(yīng)的邏輯 bean,完成 相應(yīng)的處理工作后,更新視圖 view。 view helper(視圖幫助器視圖幫助器) 將表現(xiàn)層和表現(xiàn)層的數(shù)據(jù)進(jìn)行分離,將表現(xiàn)層的數(shù)據(jù)單獨(dú)封裝一層,從而可以更加輕 松的在表現(xiàn)層進(jìn)行處理與傳遞,而與表現(xiàn)層各層低耦合,這就是 view helper 模式。 composite view(復(fù)合視圖復(fù)合視圖) 頁面層內(nèi)容繁多,如何更有效的組織與重用?復(fù)合視圖模式將一個(gè)復(fù)雜的頁面拆成多 個(gè)可重用的頁面,各頁面在程序調(diào)用過程中分別維護(hù)和顯示,從而減少了前臺(tái)頁面的復(fù) 雜性,也更容易進(jìn)行個(gè)性化和定制。 dispatcher view(派遣視圖派遣視圖) 類似于 service to worker 模式,由 front controller 和 view helper 模式組合而成。 front controller 接受請(qǐng)求,不進(jìn)行任何業(yè)務(wù)邏輯處理,立即重定向到請(qǐng)求的服務(wù)頁面,由 頁調(diào)用模型層代碼進(jìn)行處理。這個(gè)模式在視圖中進(jìn)行請(qǐng)求處理,缺點(diǎn)是不適合大型的復(fù) 雜的應(yīng)用程序開發(fā),優(yōu)點(diǎn)是頁面快速響應(yīng)。 service to worker(服務(wù)(服務(wù)/工人)工人) 與 dispatcher view 模式共同的地方是,也是由 front controller 和 view helper 模式組 合而成,不同的是,front controller 接受請(qǐng)求以后,首先進(jìn)行任何業(yè)務(wù)邏輯處理,根據(jù)處 理結(jié)果的不同,而定位到相應(yīng)的響應(yīng)視圖,適合用于大型的復(fù)雜業(yè)務(wù)邏輯的應(yīng)用系統(tǒng)。 業(yè)務(wù)層模式業(yè)務(wù)層模式 business delegate(業(yè)務(wù)代理)(業(yè)務(wù)代理) 第6頁,共78頁 如何減少表現(xiàn)層與數(shù)據(jù)層的耦合問題,業(yè)務(wù)代理模式將業(yè)務(wù)邏輯做了封裝,同時(shí)也將 數(shù)據(jù)層的接口做了進(jìn)一步抽象,從而緩存了調(diào)用邏輯,減少了調(diào)用開銷。 value object(值對(duì)象)(值對(duì)象) 如何解決表現(xiàn)層與業(yè)務(wù)層之間的數(shù)據(jù)交換,以及層內(nèi)部的數(shù)據(jù)交換問題呢?將常用的 數(shù)據(jù)單獨(dú)封裝成一個(gè) javabean,這樣便于傳遞,也便于取值與設(shè)置值。與 map 接口不同 的是,vo 更方便對(duì)值進(jìn)行操作。 value object assembler(值對(duì)象匯編器)(值對(duì)象匯編器) 將不同的值對(duì)象組裝成一個(gè)更大的值對(duì)象,方便在表現(xiàn)層與數(shù)據(jù)層之間傳遞數(shù)據(jù)。 session faade 該模式提供了下一層接口的一個(gè)抽象視圖,而不是簡單地把下一層的 api 直接包裝起 來。常用在對(duì)實(shí)體 bean 的訪問中,以及需要開發(fā)分布式業(yè)務(wù)時(shí)裝封業(yè)務(wù)邏輯。 composite entity(復(fù)合實(shí)體)(復(fù)合實(shí)體) 用于 ejb1.1 中封裝實(shí)體 bean,已過時(shí)。 value list handler(數(shù)值清單處理器)(數(shù)值清單處理器) 值列表處理器模式創(chuàng)建一個(gè)對(duì)查詢結(jié)果集的緩存。調(diào)用者向值列表處理器發(fā)出請(qǐng)求, 值列表處理器返回所需的查詢結(jié)果。值列表處理器實(shí)現(xiàn)了迭代器模式。 service locator(服務(wù)定位器)(服務(wù)定位器) 封裝對(duì) jndi 服務(wù)器的訪問細(xì)節(jié),并且對(duì)訪問方式提供了一個(gè)單一的控制點(diǎn),利用緩沖, 效率更高。 數(shù)據(jù)層模式數(shù)據(jù)層模式 data access object(數(shù)據(jù)訪問對(duì)象)(數(shù)據(jù)訪問對(duì)象) 對(duì)數(shù)據(jù)庫實(shí)體的訪問提供了靈活的調(diào)用方式,降低了業(yè)務(wù)層與數(shù)據(jù)層之間耦合度。 service activator(服務(wù)激活器)(服務(wù)激活器) 異步處理同步 ejb 組件。 1.6 1.6 gofgof模式模式 gof 的設(shè)計(jì)模式-可復(fù)用面向?qū)ο筌浖幕A(chǔ)一書中講到了 23 種設(shè)計(jì)模式,可 謂是最流行最有影響的設(shè)計(jì)模式。gof 不是一個(gè)人,而是指四個(gè)人。它的原意是 gangs of four,就是“四人幫” ,就是指此書的四個(gè)作者:erich gamma,richard helm,ralph johnson,john vlissides。 這些模式分為三大類,創(chuàng)建性、結(jié)構(gòu)性、行為性。 創(chuàng)建性模式創(chuàng)建性模式 abstract factory 第7頁,共78頁 builder factory methohd prototype singleton 結(jié)構(gòu)性模式結(jié)構(gòu)性模式 adapter bridge composite decorater faade flyweight proxy 行為性模式行為性模式 chain of responsibility command interpreter iterator mediator memento observe state stratege template method visitor 第第2章章 數(shù)據(jù)層框架與模式數(shù)據(jù)層框架與模式 第8頁,共78頁 有了前面的基礎(chǔ),我們開始一個(gè)實(shí)際的應(yīng)用。 2.1 2.1 示例示例 譬如我們要訪問數(shù)據(jù)庫,將一張表的所有記錄查詢出來。怎么做?我們習(xí)慣是寫一個(gè) javabean,下面是這個(gè) querytable.java 的源碼: package org.plat.db; import java.sql.connection; import java.sql.drivermanager; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; import java.util.arraylist; import java.util.collection; import java.util.hashmap; import java.util.map; public class querytable public collection getall() string driver = “com.mysql.jdbc.driver“; string url = “jdbc:mysql:/localhost:3306/platdb“; connection conn = null; statement stmt = null; resultset rs = null; string sql = “select uid,uname,email from users“; collection coll = new arraylist(); map map = null; try class.forname(driver); conn = drivermanager.getconnection(url,“root“,“); stmt = conn.createstatement(); rs = stmt.executequery(sql); while(rs.next() map = new hashmap(); map.put(“uid“, rs.getstring(1); map.put(“uname“,rs.getstring(2); map.put(“email“, rs.getstring(3); coll.add(map); catch (sqlexception e) e.printstacktrace(); catch (classnotfoundexception e) e.printstacktrace(); 第9頁,共78頁 finally try if(rs!=null) rs.close(); if(stmt!=null) stmt.close(); if(conn!=null) conn.close(); catch(sqlexception e) return coll; 我們看這個(gè)類,首先連接數(shù)據(jù)庫,然后執(zhí)行查詢,將每一條記錄都封裝到一個(gè) map 中,再將 map 放在集合中,最后返回一個(gè)集合對(duì)象 。 這樣寫有什么不對(duì)勁的地方呢?首先看滿足面向?qū)ο笤O(shè)計(jì)嗎?我們說對(duì)象有三大特 征,繼承、封裝、多態(tài)。滿不滿足封裝呢?將多個(gè)不同的行為封裝在一個(gè)對(duì)象中,讓這 個(gè)對(duì)象龐大而臃腫,其本身就不滿足對(duì)象的概念。 那怎么封裝呢?封裝就是讓具體的對(duì)象去做自己該做的事情,而不是大包大攬。很明 顯,上面的 querytable 對(duì)象,即做了連接,又做了查詢,還做了返回值的封裝,封裝太 多,對(duì)象的概念模糊。我們要改變這種封裝方式。 2.2 2.2 使用模式使用模式 vo 模式模式 value object 模式認(rèn)為,大量分散的數(shù)據(jù)不利于傳輸,也不利于對(duì)數(shù)據(jù)進(jìn)行操縱,必 須封裝為一個(gè)對(duì)象用來傳值。上面的例子中,users 表的三個(gè)字段被封裝在 map 接口中, 雖然不影響使用,但缺點(diǎn)有二,一是沒有體現(xiàn)對(duì)象的封裝性,我們不知道 map 中有什么 東西,map 到底代表了哪一種對(duì)象;二是 map 不利數(shù)據(jù)的獲取與設(shè)置。基于 vo 模式,我 們添加 org.accp.vo 包,并重新封裝 users 表的這三個(gè)字段,類 users 源代碼如下: package org.plat.vo; import java.util.date; public class users private int pk1; private string uid; private string uname; private string pwd; private string email; private date birth; public date getbirth() return birth; 第10頁,共78頁 public void setbirth(date birth) this.birth = birth; public string getemail() return email; public void setemail(string email) this.email = email; public int getpk1() return pk1; public void setpk1(int pk1) this.pk1 = pk1; public string getpwd() return pwd; public void setpwd(string pwd) this.pwd = pwd; public string getuid() return uid; public void setuid(string uid) this.uid = uid; public string getuname() return uname; public void setuname(string uname) this.uname = uname; dao 模式模式 解決了 map 封裝數(shù)據(jù)的問題之后,我們?cè)倏?,連接和查詢也不應(yīng)該是同一個(gè)對(duì)象所 做的事情,為什么這么說?一是數(shù)據(jù)對(duì)象訪問模式本身說明了數(shù)據(jù)訪問應(yīng)該是一個(gè)專門 的對(duì)象,它抽象了數(shù)據(jù)層對(duì)表的所有訪問接口,專注于對(duì)數(shù)據(jù)表的操作,如增、刪、改 查,而不管任何其它的業(yè)務(wù)邏輯,業(yè)務(wù)層將通過 dao 去訪問數(shù)據(jù)層;二是象 querytable 這樣的類會(huì)有很多,基本上一張表會(huì)有一個(gè)這樣的對(duì)象,這么多對(duì)象將都會(huì)有連接數(shù)據(jù) 第11頁,共78頁 庫的方法,這本身就不滿足對(duì)象封裝與繼承的概念。 所以,我們用 dao 模式,再創(chuàng)建一個(gè)類,專門處理對(duì) users 表的操作。類 usersdao 是 dao 模式的具體實(shí)現(xiàn)。而對(duì)于取數(shù)據(jù)庫的連接,我們?cè)俜庋b一個(gè)類 connector.java, 下面是它們的源代碼。 connector.java 的源代碼: package org.plat.db; import java.sql.connection; import java.sql.drivermanager; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; public class connector public static connection getconnection() string driver = “com.mysql.jdbc.driver“; string url = “jdbc:mysql:/localhost:3306/platdb“; connection conn = null; try class.forname(driver); conn = drivermanager.getconnection(url,“root“,“); catch (sqlexception e) e.printstacktrace(); catch (classnotfoundexception e) e.printstacktrace(); return conn; public static void close(resultset rs ,statement stmt, connection conn) try if(rs!=null) rs.close(); if(stmt!=null) stmt.close(); if(conn!=null) conn.close(); catch(sqlexception e) usersdao.java的源碼: package org.plat.dao; import java.sql.connection; import java.sql.resultset; 第12頁,共78頁 import java.sql.sqlexception; import java.sql.statement; import java.util.arraylist; import java.util.collection; import org.old.db.connector; import org.old.vo.users; public class usersdao public collection getall() connection conn = null; statement stmt = null; resultset rs = null; string sql = “select uid,uname,email from users“; collection coll = new arraylist(); users u = null; try conn = connector.getconnection(); stmt = conn.createstatement(); rs = stmt.executequery(sql); while(rs.next() u = new users(); u.setuid(rs.getstring(1); u.setuname(rs.getstring(2); u.setemail(rs.getstring(3); coll.add(u); catch (sqlexception e) e.printstacktrace(); finally connector.close(rs,stmt,conn); return coll; singleton模式模式 我們?cè)倏?connector.java,用到了許多靜態(tài)的方法,這樣有什么缺點(diǎn)呢?其實(shí) connector 是一個(gè)無狀態(tài)的 javabean,雖然其方法是靜態(tài)的,永遠(yuǎn)只分配同一塊內(nèi)存,但 其類本身卻是可以實(shí)例化成多個(gè)對(duì)象的,這沒有從根本上解決問題。 能不能只讓這個(gè)類只有一個(gè)實(shí)例,然后讓這個(gè)唯一的實(shí)例去訪問它的方法,而不需要 在所有的方法前冠以 static 修飾符呢?答案是 singleton(單例)模式,它從結(jié)構(gòu)上規(guī)定 第13頁,共78頁 了這個(gè)類只需要有一個(gè)實(shí)例,從而避免了多個(gè)實(shí)例實(shí)際共享同一個(gè)方法而帶來的資源消 耗,修改后 connecton.java 源碼如下: package org.plat.db; import java.sql.connection; import java.sql.drivermanager; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; public class connector private static connector connector = new connector(); private connector() public static connector getinstance() return connector; public connection getconnection() string driver = “com.mysql.jdbc.driver“; string url = “jdbc:mysql:/localhost:3306/platdb“; connection conn = null; try class.forname(driver); conn = drivermanager.getconnection(url,“root“,“); catch (sqlexception e) e.printstacktrace(); catch (classnotfoundexception e) e.printstacktrace(); return conn; public void close(resultset rs ,statement stmt, connection conn) try if(rs!=null) rs.close(); if(stmt!=null) stmt.close(); if(conn!=null) conn.close(); catch(sqlexception e) thread-specefic-storage模式模式 上例中的 connecton.java 的 getconnection()方法,當(dāng) web 層通過 servlet 來調(diào)用時(shí), 第14頁,共78頁 將會(huì)暴露多線程的安全問,怎么解決呢?我們可以加上同步關(guān)鍵字 synchronized,但卻是 以性能的損失為代 價(jià)的。thread-specific storage(線程專門存儲(chǔ))模式認(rèn)為,即然共用資 源困難,干脆不用共享,而為共享的資源專門為每個(gè)線程創(chuàng)建一個(gè)副本。threadlocal 是 thread local variable,為每一個(gè)使用該變量的線程都提供一個(gè)變量值的副本,而不會(huì)和其 它線程的副本沖突。 connecton.java 進(jìn)一步優(yōu)化后的源代碼如下: package org.plat.db; import java.sql.connection; import java.sql.drivermanager; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; public class connector private static connector connector = new connector(); private connector() public static connector getinstance() return connector; private static final threadlocal connthread = new threadlocal(); public connection getconnection() connection conn = (connection) connthread.get(); if(conn=null) conn = this._getconnection(); connthread.set(conn); return conn; private connection _getconnection() string driver = “com.mysql.jdbc.driver“; string url = “jdbc:mysql:/localhost:3306/platdb“; connection conn = null; try class.forname(driver); conn = drivermanager.getconnection(url,“root“,“); catch (sqlexception e) e.printstacktrace(); 第15頁,共78頁 catch (classnotfoundexception e) e.printstacktrace(); return conn; public void close(resultset rs ,statement stmt, connection conn) try if(rs!=null) rs.close(); if(stmt!=null) stmt.close(); if(conn!=null) conn.close(); catch(sqlexception e) 事務(wù)事務(wù) 再看 usersdao.java 的源碼,首先獲取連接,然后取出表中所有的記錄,最后釋放資 源關(guān)閉連接。乍一看似乎沒有什么不妥,其實(shí)不然。 想象這樣一種情況,如果我們?cè)偬砑佣埍?,一張是崗位?duty,另一張是用戶與崗 位關(guān)聯(lián)的中間表 user_duty?,F(xiàn)在要查看用戶表 users 找到張三的記錄,再將其刪除,同時(shí) 刪除用戶崗位表 user_duty 中張三的所有崗位。這一系列的操作,其實(shí)是一個(gè)事務(wù),任何 時(shí)候,為了保證數(shù)據(jù)的一致性,要么全部提交成功,要么全部提交失敗,不允許出現(xiàn)刪 除張三失敗但刪除崗位成功的情況。 再看我們的例子,我們的 usersdao 中的方法都是自己取連接,用完后自己關(guān)閉,自 產(chǎn)自銷,根本不能滿足我們的要求,這時(shí)候,我們需要將 connection 中的提交方式改為 手動(dòng)提交,如果成功,提交,否則全部回滾。為了體現(xiàn)面向?qū)ο蟮姆庋b,我們?cè)賱?chuàng)建一 個(gè)事務(wù)類,transaction.java: package org.plat.db; import java.sql.connection; import java.sql.sqlexception; public class transaction connection con = null; /* * bool為真表明是自動(dòng)提交,為假則是有事務(wù)需手動(dòng)提交 */ public transaction(boolean bool) 第16頁,共78頁 try con = connector.getinstance().getconnection(); con.setautocommit(bool); catch (sqlexception e) e.printstacktrace(); public connection getconn() throws sqlexception return con; public void commit() if (con != null) try mit(); catch (sqlexception e) e.printstacktrace(); public void rollback() if (con != null) try con.rollback(); catch (sqlexception e) e.printstacktrace(); public void close() if (con != null) try mit(); catch (sqlexception e) e.printstacktrace(); 2.3 2.3 使用設(shè)計(jì)原則使用設(shè)計(jì)原則 ioc原則原則 第17頁,共78頁 我們?cè)倏?org.plat.usersdao 類,加上事務(wù)后,不再擔(dān)心數(shù)據(jù)一致性的問題了,連接的 獲取不再是直接調(diào)用 connector 的 getconnection()方法,而必須從事務(wù)中得到。這時(shí)又出 現(xiàn)問題,怎么獲取事務(wù)呢?是自己直接 new 一個(gè)事務(wù),然后取連接嗎?很顯然,這還是 沒有解決事務(wù)的問題,即還是自己創(chuàng)建事務(wù)取連接,然后關(guān)閉事務(wù)。同時(shí)也違反了 ioc(inverse of control,控制反轉(zhuǎn)原則) ,即不用關(guān)心事務(wù)是怎么創(chuàng)建的,誰創(chuàng)建的,我 只關(guān)心怎么使用事務(wù)就行了。而 ioc 有四種方式,此處我們采用 set 方法傳遞事務(wù)。修正 后的 usersdao 源代碼如下: package org.plat.dao; import java.sql.connection; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; import java.util.arraylist; import java.util.collection; import org.old.db.connector; import org.old.vo.users; import org.plat.db.transaction; public class usersdao private transaction transaction; public transaction gettransaction() return transaction; public void settransaction(transaction transaction) this.transaction = transaction; public collection getall() connection conn = null; statement stmt = null; resultset rs = null; string sql = “select uid,uname,email from users“; collection coll = new arraylist(); users u = null; try conn = gettransaction().getconn(); stmt = conn.createstatement(); rs = stmt.executequery(sql); 第18頁,共78頁 while(rs.next() u = new users(); u.setuid(rs.getstring(1); u.setuname(rs.getstring(2); u.setemail(rs.getstring(3); coll.add(u); catch (sqlexception e) e.printstacktrace(); finally connector.close(rs,stmt,null); return coll; 里氏代換原則里氏代換原則 再看上面的 usersdao 類,發(fā)現(xiàn)當(dāng)有許多表時(shí),基本上是每張表都會(huì)有一個(gè)對(duì)應(yīng)的 dao 類,這樣將在每個(gè) dao 類里面都封裝了一段共同的代碼,即對(duì)事務(wù)的獲取和設(shè)置。用 里氏代換原則可以解決這個(gè)問題,即任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。我 們可以將這段共同代碼封裝成一個(gè)基類,讓這些 dao 子類去繼承。 根據(jù)以上原則,我們?cè)俣x一個(gè) parentdao,作為所有 dao 的父類,封裝事務(wù)。 parentdao.java package org.plat.dao; import org.plat.db.transaction; public class parentdao private transaction transaction; public transaction gettransaction() return transaction; public void settransaction(transaction transaction) this.transaction = transaction; isp 原則原則 第19頁,共78頁 前面提到,當(dāng)有多張表時(shí),將會(huì)有多個(gè) dao,如此多的 dao,它們都是數(shù)據(jù)訪問對(duì)象, 都有類似的方法,如增、刪、改、查等,能不能抽象出一個(gè)共同的接口,便于管理和擴(kuò) 展呢?答案是顯而易見的。在抽象成接口時(shí),要有哪些方法,這必須滿足 isp(interface- segregation principle,接口隔離原則)應(yīng)盡可能提供小的單獨(dú)的接口,而不是大的總接口。 由 isp 原則,我們?cè)俪橄笠粋€(gè)接口,idao.java,所有的子類 dao 去實(shí)現(xiàn)這個(gè)接口。 package org.plat.dao; import java.sql.sqlexception; import java.util.collection; public interface idao /* * 保存信息 */ public boolean save(object vo) throws sqlexception ; /* * 由主鍵或其它字段刪除信息 */ public boolean delete(object vo) throws sqlexception; /* * 由主鍵修改信息 */ public boolean upd(object vo) throws sqlexception; /* * 由主鍵或其它字段查找用戶信息 */ public object find(object vo) throws sqlexception; /* * 查找表中所有記錄信息 */ public collection findall() throws sqlexception ; 多態(tài)多態(tài) 再 看上面的 idao 接口,我們方法中的參數(shù)和返回值都定義為 object 對(duì)象,因?yàn)槊繌?表都將有一個(gè)對(duì)應(yīng)的 vo,所有的 vo 都是繼承 object 對(duì)象,于是我們可以用面向?qū)ο蟮奶?征之一多態(tài)來解決這個(gè)共同的傳值問題,即特殊動(dòng)態(tài)綁定。 仔細(xì)想一想,特殊動(dòng)態(tài)綁定固然解決了傳值問題,但也暴露一些隱患。其一,任何類 第20頁,共78頁 都是 object 對(duì)象,將造成傳值時(shí)類型錯(cuò)誤,編譯器檢查不到的問題,而這個(gè)問題本該在 編譯時(shí)解決。其二,object 封裝的對(duì)象層面太抽象,不能一目了然的看出這個(gè)參數(shù)的用意, 也失去了面向?qū)ο蠓庋b的特性。 基于以上觀點(diǎn),我們?cè)俜庋b一個(gè)抽象類,讓所有的值對(duì)象 vo 都去繼承這個(gè)基類。然 后修改 idao 接口,用這個(gè)抽象類去傳遞參數(shù)。 valueobject.java package org.plat.vo; import java.io.serializable; public abstract class valueobject implements serializable private string memo; public string getmemo() return memo; public void setmemo(string memo) this.memo = memo; ocp原則原則 再看 org.plat.db 包中的 connector 類,它主要的方法是 getconnection() ,從數(shù)據(jù)庫中 取連接。假設(shè)現(xiàn)在需求有了改動(dòng),要將 mysql 數(shù)據(jù)庫改為 sqlserver 數(shù)據(jù)庫,我們是不是 要改這個(gè)方法呢? 當(dāng)然要改,不改數(shù)據(jù)庫都連不上了。修改本身固然沒有問題,但是,它顯然違反了面 向?qū)ο蟮囊粋€(gè)核心原則ocp(open close principle,開閉原則) ,對(duì)擴(kuò)展開放,對(duì)修改關(guān) 閉。在前期的設(shè)計(jì)中,我們應(yīng)該盡可能的抽象出更多的方法,以便項(xiàng)目的擴(kuò)展與維護(hù), 而不是一有問題就改原來的類與方法,進(jìn)行重構(gòu)。 既然我們現(xiàn)在就能料到日后可能有多個(gè)數(shù)據(jù)庫的問題,這里我們必須要考慮到擴(kuò)展, 怎么去做,抽象類。抽象類是 ocp 原則的體現(xiàn),我們?cè)俣x一個(gè) connector 的抽象類, 將關(guān)閉方法提取到這里,connector.java 源代碼如下: package org.plat.db; 第21頁,共78頁 import java.sql.connection; import java.sql.preparedstatement; import java.sql.resultset; import java.sql.statement; public abstract class connector public abstract connection getconnectionfrommysql(); public abstract connection getconnectionfromsqlserver(); public void close(resultset rs, preparedstatement pst, statement st, connection conn) try if(rs!=null) rs.close(); if(pst!=null) pst.close(); if(st!=null) st.close(); if(conn!=null) conn.close(); catch(exception e) 再寫一個(gè)子類 connectorimpl 去實(shí)現(xiàn) connector,其中的 getconnectionfromsqlserver() 方法可以不實(shí)現(xiàn),待日后擴(kuò)展用。這樣新的需求出現(xiàn),不需要改動(dòng)原來的類結(jié)構(gòu),只需 要將方法體補(bǔ)上即可。 2.4 2.4 框架框架初步初步 將上面的源代碼整理,畫出它們的 uml 圖如下: idao (from dao) usersdao (from dao) connector (from db) connectorimpl (from db) -$connector transaction (from db) parentdao (from dao) users (from vo) valueobject (from vo) 從圖上可以看出,userdao 類實(shí)現(xiàn)了 idao 接口并繼承了 parentdao,而 parentdao 又 與事務(wù)類 transaction 單向關(guān)聯(lián)。 usersdao 又調(diào)用 connectorimpl,后者與自己自反關(guān)聯(lián),并且繼承了抽象類 第22頁,共78頁 connector。他們?cè)谡{(diào)用時(shí)通過 valueobject 類來傳遞參數(shù)。 users 類繼承了 valueobject,主要用來封裝數(shù)據(jù)庫表的字段,并傳遞參數(shù)。 整理它們的源代碼,得到如下的清單。 清單清單 1:valueobject.java package org.plat.vo; import java.io.serializable; public abstract class valueobject implements serializable private string memo; public string getmemo() return memo; public void setmemo(string memo) this.memo = memo; 清單清單 2:users.java package org.plat.vo; import java.util.date; public class users extends valueobject private int pk1; private string uid; private string uname; private string pwd; private string email; private date birth; public date getbirth() return birth; public void setbirth(date birth) this.birth = birth; public string getemail() return email; public void setemail(string email) 第23頁,共78頁 this.email = email; public int getpk1() return pk1; publi

溫馨提示

  • 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)論