1. 程式人生 > >一個體現Java介面及工廠模式優點的例子(經典)

一個體現Java介面及工廠模式優點的例子(經典)

一個體現Java介面及工廠模式優點的例子(轉載自http://www.jspcool.com/j2se/20071019225405.htm) 隨著模式概念的普及,瞭解模式和使用模式的程式設計師越來越多,很多人在學習模式的時候,都會有這樣一種疑惑:“有必要搞得這麼複雜嗎?”。的確,因為教程的例子過於簡單化(這樣方便讀者學習),或者是作者選例子的時候並沒有很好體現所講模式的優點,很多情況下如果僅就其例子的問題來說,用模式是太複雜了。因此才導致這樣的誤解:“模式就是把簡單的問題複雜化嗎?”。當然不是,隨著你開發實踐的不斷豐富,你終會發現模式強大威力,而且模式也並非貴族化的程式設計方式,它就是一些經過提煉了的解決問題的方法技巧。 通過學習模式,程式設計師開始告別過去準直線式的程式碼方式,模式開擴了我們的視野,強化了我們面向物件程式設計的思維方式。然而現在又出現了另一個普遍的問題,盲目應用模式。模式是問題的解決方案,先有問題才有模式,模式是依附於所要解決的問題的而生的。必須瞭解模式在很多情況下是以提高程式碼的複雜度為代價來增強靈活性、可複用性。如果在自已的程式碼中使用某一模式僅只提高了程式碼的複雜度,而其它方面收效甚微,或者某部份程式碼根本就不存在靈活性及高複用性的需求,那麼我們就沒有必要為使用模式而放棄更直觀簡單的程式碼寫法。 一流的高手90%精力關注問題的解決方案,因為找到了好的解決方案,再寫起程式碼會很輕鬆程式碼也簡潔流暢,看這樣的程式碼是一種享受和提高;二流的熟手90%精力關注程式碼實現,因為問題的解決方案並非最佳,實現的程式碼也會比較複雜;三流菜鳥記流水帳,90%精力在敲鍵盤,常常做了大半才發現行不通,回過頭來再用90%的時間敲鍵盤,根本不會用到任何模式,寫出來的程式碼的只有他自已才能看懂。做出來的軟體也是支離破碎,做一丁點改動都要大費周折,而且你還不知道改動後會產生什麼問題,大有住危房裡的感覺。 在這裡還是舉一個濫用模式的例子吧。我曾參與過一個大集團公司OA系統的第二期開發,開發沿用原有程式碼架構並增加新的功能模組。文件很少我讀原始碼時就被它程式裡的程式碼轉來轉去搞得頭大如鬥,最後讀懂了:原始碼架構總體採用工廠模式,而且是最複雜的抽象工廠模式。它把所有模組類都通過工廠生成還工廠套工廠,並且每一個模組類都有一個介面,每個介面也只有一個模組現實類,因為涉及許可權控制還用了代理(proxy)模式。 讀懂程式碼後我開始嵌入程式碼,發現每新增一個類,都要到六個Java檔案中去增加相應程式碼,而在類中每增加一個方法,也要到它的介面等四個Java檔案中去增加相應程式碼。天呀!!!記得當時我的小姆指常會不聽使喚,就是因為頻繁的使用Ctrl+C 、Ctrl+V,小姆指按著Ctrl鍵給累的。整個專案組苦不堪言,真煩透了。專案結束後我回顧發現:代理模式用得還對(現在針對許可權這類橫向控制有AOP程式設計這種新的解決辦法了)但工廠模式在這裡根本就是畫蛇添足,不僅沒有解決什麼問題,反而增加程式碼複雜度和耦合性,降低了開發效率連維護難度都提高了。而且那種每個類簡單的加一個介面的方式,更是沒有道理,這讓我很想說周星馳說過的一句話:“球~~~不是這麼踢~~~~的,介面~~~不是這麼用~~~的”。言歸正傳,我們先來看這樣一個常見問題:某系統需要支援多種型別的資料庫。用過Oracle、MSSQL等資料庫的人都知道,它們的SQL編寫方式都各有些不同。比如說Oracle的唯一標識自動+1欄位用的是序列,MSSQL改一下欄位屬性就成了,還有各種各自特有的SQL用法。為了支援多資料庫,難道我們要開發多套系統?當然NO。請看下面的解決方案。 即然資料庫存在多種,我們可以將系統中所有對資料庫的操作抽象出來,寫成一個個方法組合到一個類中,有幾種資料庫我們就寫幾個這樣的類。具體設計類圖如下: 簡要說明: OracleDataOperate、SqlserverDataOperate、MysqlDataOperate,分別代表Oracle、Sqlserver、Mysql這三種資料庫的操作類。繼承自AbstractDataOperate AbstractDataOperate是一個抽象類,包含了那些不同種類資料庫都是一樣程式碼的操作方法。繼承自DataOperate DataOperate是上面說的資料操作類的統一介面,只有兩個方法:取得一條記錄、插入一條記錄。 DataOperateFactory是一個工廠方法,統一用它的方法來得到資料庫操作類的例項。 SampleClass是我們系統的某個功能模組的類。 People是一個實體類,代表一條記錄。三個欄位 oid唯一識別符號、name姓名、date生日。 詳細說明: 1、所有系統功能模組類只認DataOperat這個介面還不必管具體的實現類是OracleDataOperate還SqlserverDataOperate。DataOperate原始碼如下: public interface DataOperate { //根據記錄的唯一標識取出一條記錄 People getPeople(String oid); //插入一條記錄 boolean insertPeople(People people); } 2、AbstractDataOperate、OracleDataOperate、SqlserverDataOperate、MysqlDataOperate都是繼承DataOperate介面的,沒什麼好說的,省略。 3、DataOperateFactory。我們看看工廠方法怎麼寫的。 public class DataOperateFactory { public static final int ORACLE = 0; //定義三個表示資料庫型別的常量 public static final int MYSQL = 1; public static final int SQLSERVER = 2; private static DataOperate db; private static int dataType = MYSQL; /** * 根據資料庫型別(dataType)取得一個數據庫操作類的例項, * 這裡對DataOperate使用了單例模式,因為OracelDataOperate等都是無狀態的工具類, * 所以整個系統只保留一個例項就行了。 * * @return 返回的是介面,客戶端不必關心具體是用那個實現類 */ public static DataOperate getInstance() { if (db == null) { if (dataType == ORACLE) //根據dateType返回相應的實現類 return new OracelDataOperate(); if (dataType == MYSQL) return new MysqlDataOperate(); if (dataType == SQLSERVER) return new SqlserverDataOperate(); } return db; } } 4、接下來就看看使用端是如何呼叫工廠方法和使用資料操作類的。 /** * 系統某個功能類 */ public class SampleClass { private DataOperate db; //宣告一個數據庫操作類,注意這裡用的是介面噢 /**某方法*/ public void sampleMethod() { db = DataOperateFactory.getInstance();//得到單一例項 People p = db.getPeople("123"); //取得一條記錄 db.insertPeople(p);//再插回去 } }   我們發現SampleClass中根本沒有出現OracelDataOperate、MysqlDataOperate等的影子,這就是介面的威力。客戶端不必針對OracelDataOperate等寫不同的程式碼,它只關心DataOperate即可,具體要取那個類的邏輯就由DataOperateFactory負責了。 總結: 從例子中我們可以看到什麼是面向介面的程式設計方式。SampleClass使用資料操作類可以不必關心具體是那個類,只要是符合介面的都行 要例項?只須呼叫DataOperateFactory.getInstance()即可,其它的交於DataOperateFactory這個工廠來做吧,使用端什麼都不用關心。 我們要支援新的資料庫型別,只須要象OracelDataOperate那樣,再寫一個繼承AbstractDataOperate的類即可,比如SysbaseDataOperate。然後到DataOperateFactory中加入相應程式碼即可。 如果我們想要可配置性更高,可以用private static int dataType = MYSQL;中的值設定到一個文字檔案中。   對於開發支援多種資料庫的系統,強烈建議使用hibernate,我現在做的系統就是用hibernate的,開發時用Mysql,到要給客戶時將資料庫換了DB2,程式不用做任何改動,真正的無逢移植。不過這樣,本文所提到的方法就沒什麼用了. 這兩篇是我找到的關於Factory Mode的文章,但是前面的論述很好,後面的例子卻不怎麼樣,特別是第二篇的例子並不符合實際也沒必要這樣做,純粹是介面也可以實現,Factory Mode並沒有體現多少。第一篇的就似乎比較切實,但是說的也不夠清晰。