模式與框架-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),請進(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)新,不斷完善,所以舊的模式會發(fā)現(xiàn)不再適用,而新的模式會出現(xiàn)。 模式在各個應(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)成一個可用的業(yè)務(wù)系統(tǒng)?;诳?架的開發(fā)可以節(jié)省大量的精力而致力于系統(tǒng)的業(yè)務(wù)邏輯設(shè)計(jì)。 譬如在建筑領(lǐng)域,屋架、梁柱就是一個典型的框架,是一個半成品。屋架的作用是 承重,但不能遮風(fēng)擋雨,必須在上面蓋瓦或鋪設(shè)覆蓋物,形成屋頂,才能具備完整的功 能;糧柱的其本作用是劃分空間、承受垂直與橫向的壓力,但不具備封閉空間、隔聲的 效果,尚待在柱間砌筑墻體,在梁間鋪設(shè)樓板才能居住。 在軟件開發(fā)中,框架僅提供了部分通用的功能,還必須經(jīng)過業(yè)務(wù)的填充,才能形成一 個功能齊全的業(yè)務(wù)系統(tǒng)。 1.3 1.3 模式與框架的區(qū)別模式與框架的區(qū)別 從規(guī)模上講,模式專注于微觀層面的分析與設(shè)計(jì),而框架著眼于宏觀的構(gòu)造。 從實(shí)現(xiàn)的角度看,模式只是一種解決問題的方法,一個解決方案,而框架卻是一個實(shí) 現(xiàn)這種方案的具體的產(chǎn)品,有著實(shí)際的功效與作用。 從關(guān)系上講,模式是框架的理論基礎(chǔ),多個模式的實(shí)現(xiàn)構(gòu)成了一個框架。框架是模式 的具體實(shí)現(xiàn),一個局部或全局的框架,一般都要用到模式。 既然是框架,本身就表示它是一種好的通用的產(chǎn)品,怎么體現(xiàn)它是好的呢,模式恰好 證明了它是解決某一類問題的最好的解決方案,所以說,沒有用到模式的框架,將不是 一個良好的可用的框架。 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 模式:主要針對系統(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 的分層,在每一層都提出了幾種模式,這些模式分別組成各層,最后組成一個完整 第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(截獲過濾截獲過濾) 對請求和響應(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)用模型層的類來處理請求,然后將 處理后的信息轉(zhuǎn)發(fā)到響應(yīng)頁面進(jìn)行展示,絕不能將業(yè)務(wù)邏輯代碼堆砌在 servlet 方法中。 那么如何能體現(xiàn) servlet 的這一功能需求呢,前端控制器模式很好的解決了這個問題,在 一個項(xiàng)目中,只有一個控制器,它是系統(tǒng)的一個入口,由他調(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ù)合視圖模式將一個復(fù)雜的頁面拆成多 個可重用的頁面,各頁面在程序調(diào)用過程中分別維護(hù)和顯示,從而減少了前臺頁面的復(fù) 雜性,也更容易進(jìn)行個性化和定制。 dispatcher view(派遣視圖派遣視圖) 類似于 service to worker 模式,由 front controller 和 view helper 模式組合而成。 front controller 接受請求,不進(jìn)行任何業(yè)務(wù)邏輯處理,立即重定向到請求的服務(wù)頁面,由 頁調(diào)用模型層代碼進(jìn)行處理。這個模式在視圖中進(jìn)行請求處理,缺點(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 接受請求以后,首先進(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ù)據(jù)層的接口做了進(jìn)一步抽象,從而緩存了調(diào)用邏輯,減少了調(diào)用開銷。 value object(值對象)(值對象) 如何解決表現(xiàn)層與業(yè)務(wù)層之間的數(shù)據(jù)交換,以及層內(nèi)部的數(shù)據(jù)交換問題呢?將常用的 數(shù)據(jù)單獨(dú)封裝成一個 javabean,這樣便于傳遞,也便于取值與設(shè)置值。與 map 接口不同 的是,vo 更方便對值進(jìn)行操作。 value object assembler(值對象匯編器)(值對象匯編器) 將不同的值對象組裝成一個更大的值對象,方便在表現(xiàn)層與數(shù)據(jù)層之間傳遞數(shù)據(jù)。 session faade 該模式提供了下一層接口的一個抽象視圖,而不是簡單地把下一層的 api 直接包裝起 來。常用在對實(shí)體 bean 的訪問中,以及需要開發(fā)分布式業(yè)務(wù)時裝封業(yè)務(wù)邏輯。 composite entity(復(fù)合實(shí)體)(復(fù)合實(shí)體) 用于 ejb1.1 中封裝實(shí)體 bean,已過時。 value list handler(數(shù)值清單處理器)(數(shù)值清單處理器) 值列表處理器模式創(chuàng)建一個對查詢結(jié)果集的緩存。調(diào)用者向值列表處理器發(fā)出請求, 值列表處理器返回所需的查詢結(jié)果。值列表處理器實(shí)現(xiàn)了迭代器模式。 service locator(服務(wù)定位器)(服務(wù)定位器) 封裝對 jndi 服務(wù)器的訪問細(xì)節(jié),并且對訪問方式提供了一個單一的控制點(diǎn),利用緩沖, 效率更高。 數(shù)據(jù)層模式數(shù)據(jù)層模式 data access object(數(shù)據(jù)訪問對象)(數(shù)據(jù)訪問對象) 對數(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 不是一個人,而是指四個人。它的原意是 gangs of four,就是“四人幫” ,就是指此書的四個作者: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ǔ),我們開始一個實(shí)際的應(yīng)用。 2.1 2.1 示例示例 譬如我們要訪問數(shù)據(jù)庫,將一張表的所有記錄查詢出來。怎么做?我們習(xí)慣是寫一個 javabean,下面是這個 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; 我們看這個類,首先連接數(shù)據(jù)庫,然后執(zhí)行查詢,將每一條記錄都封裝到一個 map 中,再將 map 放在集合中,最后返回一個集合對象 。 這樣寫有什么不對勁的地方呢?首先看滿足面向?qū)ο笤O(shè)計(jì)嗎?我們說對象有三大特 征,繼承、封裝、多態(tài)。滿不滿足封裝呢?將多個不同的行為封裝在一個對象中,讓這 個對象龐大而臃腫,其本身就不滿足對象的概念。 那怎么封裝呢?封裝就是讓具體的對象去做自己該做的事情,而不是大包大攬。很明 顯,上面的 querytable 對象,即做了連接,又做了查詢,還做了返回值的封裝,封裝太 多,對象的概念模糊。我們要改變這種封裝方式。 2.2 2.2 使用模式使用模式 vo 模式模式 value object 模式認(rèn)為,大量分散的數(shù)據(jù)不利于傳輸,也不利于對數(shù)據(jù)進(jìn)行操縱,必 須封裝為一個對象用來傳值。上面的例子中,users 表的三個字段被封裝在 map 接口中, 雖然不影響使用,但缺點(diǎn)有二,一是沒有體現(xiàn)對象的封裝性,我們不知道 map 中有什么 東西,map 到底代表了哪一種對象;二是 map 不利數(shù)據(jù)的獲取與設(shè)置?;?vo 模式,我 們添加 org.accp.vo 包,并重新封裝 users 表的這三個字段,類 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ù)的問題之后,我們再看,連接和查詢也不應(yīng)該是同一個對象所 做的事情,為什么這么說?一是數(shù)據(jù)對象訪問模式本身說明了數(shù)據(jù)訪問應(yīng)該是一個專門 的對象,它抽象了數(shù)據(jù)層對表的所有訪問接口,專注于對數(shù)據(jù)表的操作,如增、刪、改 查,而不管任何其它的業(yè)務(wù)邏輯,業(yè)務(wù)層將通過 dao 去訪問數(shù)據(jù)層;二是象 querytable 這樣的類會有很多,基本上一張表會有一個這樣的對象,這么多對象將都會有連接數(shù)據(jù) 第11頁,共78頁 庫的方法,這本身就不滿足對象封裝與繼承的概念。 所以,我們用 dao 模式,再創(chuàng)建一個類,專門處理對 users 表的操作。類 usersdao 是 dao 模式的具體實(shí)現(xiàn)。而對于取數(shù)據(jù)庫的連接,我們再封裝一個類 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模式模式 我們再看 connector.java,用到了許多靜態(tài)的方法,這樣有什么缺點(diǎn)呢?其實(shí) connector 是一個無狀態(tài)的 javabean,雖然其方法是靜態(tài)的,永遠(yuǎn)只分配同一塊內(nèi)存,但 其類本身卻是可以實(shí)例化成多個對象的,這沒有從根本上解決問題。 能不能只讓這個類只有一個實(shí)例,然后讓這個唯一的實(shí)例去訪問它的方法,而不需要 在所有的方法前冠以 static 修飾符呢?答案是 singleton(單例)模式,它從結(jié)構(gòu)上規(guī)定 第13頁,共78頁 了這個類只需要有一個實(shí)例,從而避免了多個實(shí)例實(shí)際共享同一個方法而帶來的資源消 耗,修改后 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)用時, 第14頁,共78頁 將會暴露多線程的安全問,怎么解決呢?我們可以加上同步關(guān)鍵字 synchronized,但卻是 以性能的損失為代 價的。thread-specific storage(線程專門存儲)模式認(rèn)為,即然共用資 源困難,干脆不用共享,而為共享的資源專門為每個線程創(chuàng)建一個副本。threadlocal 是 thread local variable,為每一個使用該變量的線程都提供一個變量值的副本,而不會和其 它線程的副本沖突。 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í)不然。 想象這樣一種情況,如果我們再添加二張表,一張是崗位表 duty,另一張是用戶與崗 位關(guān)聯(lián)的中間表 user_duty?,F(xiàn)在要查看用戶表 users 找到張三的記錄,再將其刪除,同時 刪除用戶崗位表 user_duty 中張三的所有崗位。這一系列的操作,其實(shí)是一個事務(wù),任何 時候,為了保證數(shù)據(jù)的一致性,要么全部提交成功,要么全部提交失敗,不允許出現(xiàn)刪 除張三失敗但刪除崗位成功的情況。 再看我們的例子,我們的 usersdao 中的方法都是自己取連接,用完后自己關(guān)閉,自 產(chǎn)自銷,根本不能滿足我們的要求,這時候,我們需要將 connection 中的提交方式改為 手動提交,如果成功,提交,否則全部回滾。為了體現(xiàn)面向?qū)ο蟮姆庋b,我們再創(chuàng)建一 個事務(wù)類,transaction.java: package org.plat.db; import java.sql.connection; import java.sql.sqlexception; public class transaction connection con = null; /* * bool為真表明是自動提交,為假則是有事務(wù)需手動提交 */ 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頁 我們再看 org.plat.usersdao 類,加上事務(wù)后,不再擔(dān)心數(shù)據(jù)一致性的問題了,連接的 獲取不再是直接調(diào)用 connector 的 getconnection()方法,而必須從事務(wù)中得到。這時又出 現(xiàn)問題,怎么獲取事務(wù)呢?是自己直接 new 一個事務(wù),然后取連接嗎?很顯然,這還是 沒有解決事務(wù)的問題,即還是自己創(chuàng)建事務(wù)取連接,然后關(guān)閉事務(wù)。同時也違反了 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)有許多表時,基本上是每張表都會有一個對應(yīng)的 dao 類,這樣將在每個 dao 類里面都封裝了一段共同的代碼,即對事務(wù)的獲取和設(shè)置。用 里氏代換原則可以解決這個問題,即任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。我 們可以將這段共同代碼封裝成一個基類,讓這些 dao 子類去繼承。 根據(jù)以上原則,我們再定義一個 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)有多張表時,將會有多個 dao,如此多的 dao,它們都是數(shù)據(jù)訪問對象, 都有類似的方法,如增、刪、改、查等,能不能抽象出一個共同的接口,便于管理和擴(kuò) 展呢?答案是顯而易見的。在抽象成接口時,要有哪些方法,這必須滿足 isp(interface- segregation principle,接口隔離原則)應(yīng)盡可能提供小的單獨(dú)的接口,而不是大的總接口。 由 isp 原則,我們再抽象一個接口,idao.java,所有的子類 dao 去實(shí)現(xiàn)這個接口。 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 對象,因?yàn)槊繌?表都將有一個對應(yīng)的 vo,所有的 vo 都是繼承 object 對象,于是我們可以用面向?qū)ο蟮奶?征之一多態(tài)來解決這個共同的傳值問題,即特殊動態(tài)綁定。 仔細(xì)想一想,特殊動態(tài)綁定固然解決了傳值問題,但也暴露一些隱患。其一,任何類 第20頁,共78頁 都是 object 對象,將造成傳值時類型錯誤,編譯器檢查不到的問題,而這個問題本該在 編譯時解決。其二,object 封裝的對象層面太抽象,不能一目了然的看出這個參數(shù)的用意, 也失去了面向?qū)ο蠓庋b的特性。 基于以上觀點(diǎn),我們再封裝一個抽象類,讓所有的值對象 vo 都去繼承這個基類。然 后修改 idao 接口,用這個抽象類去傳遞參數(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)在需求有了改動,要將 mysql 數(shù)據(jù)庫改為 sqlserver 數(shù)據(jù)庫,我們是不是 要改這個方法呢? 當(dāng)然要改,不改數(shù)據(jù)庫都連不上了。修改本身固然沒有問題,但是,它顯然違反了面 向?qū)ο蟮囊粋€核心原則ocp(open close principle,開閉原則) ,對擴(kuò)展開放,對修改關(guān) 閉。在前期的設(shè)計(jì)中,我們應(yīng)該盡可能的抽象出更多的方法,以便項(xiàng)目的擴(kuò)展與維護(hù), 而不是一有問題就改原來的類與方法,進(jìn)行重構(gòu)。 既然我們現(xiàn)在就能料到日后可能有多個數(shù)據(jù)庫的問題,這里我們必須要考慮到擴(kuò)展, 怎么去做,抽象類。抽象類是 ocp 原則的體現(xiàn),我們再定義一個 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) 再寫一個子類 connectorimpl 去實(shí)現(xiàn) connector,其中的 getconnectionfromsqlserver() 方法可以不實(shí)現(xiàn),待日后擴(kuò)展用。這樣新的需求出現(xiàn),不需要改動原來的類結(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。他們在調(diào)用時通過 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等.壓縮文件請下載最新的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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論