什麼是設計模式?
如果一個問題一再地出現,就必須找到一個能夠有效解決問題的方法。那個方法就被描述成模式。設計模式是獨立於編程語言的,用來解決常見的,面向對象的設計問題的策略。當你實施設計的時候,你應該知曉一些常見的解決之道的名稱。通曉設計模式可以使人們相互間做有效的交流。實際上,你可能已經對一些設計模式很熟悉了,你只是沒有用大家耳熟能詳的稱謂來描述它們而已。太陽公司建議使用GOF(“四人幫”,指寫了“設計模式-可重復使用的面向對象軟件的元素”一書的四位先驅),所以我們應用那本書作為指導來描述解決之道。你也需要讓自己對這些術語熟悉起來,看看別人是如何用它們來解決編程問題的。
一定要使用設計模式嗎?
如果你希望成為一位Java的職業程序員,你至少應當曉得一些很流行的解決編碼問題的方法。這些方法已被有經驗的程序員在實踐中證明非常有效。它們就是所謂的設計模式。學習設計模式可以加速你在OOA/OOD領域的經驗積累。一旦你掌握了它們,你將會終生收益,並讓自己成為設計和開發領域的大師。而且,你也可以使用這些術語和你的同行們更高效地交流。
許多有多年經驗的程序員並不知道設計模式,但是作為一個OO的程序員,你必須熟知它們,特別是對那些新學Java的人。實際上,當你解決一個編程問題時,你就已經在使用設計模式了。你只是沒有用一些流行的術語來稱呼它們而已,或者沒有選擇一個有效地方法從知識產權的角度來更好地控制你的成果。學習有經驗的開發人員是如何來解決編程問題的,並應用到你自己的項目上去是贏得經驗和證明的最好方法。
記住,學習設計模式一定會改變你編程的方法;你不只是會變得睿智,你會變得非常的睿智。
有多少設計模式?
許多。一個網站上說在OO的領域中,至少有250種模式,包括“意大利面條”式(指低效糟糕的代碼)。被GOF應用的23種設計模式廣為人知,許多模式還在探索和發現中。
對了,提醒一句,設計模式不是術語,算法,或組件。
設計模式間的相互關系
一般來講,建造一個系統,需要將許多設計模式編排在一起。不同的設計師可能使用不同的模式來解決同一個問題。通常來說:
一些模式間相處和諧
一個模式可以引發出另一個模式
一些模式很類似,可以相互替代
模式是可以被發現並文檔化的
模式不是方法或架構
模式可以給出一些有效解決問題的提示
創建性模式
抽象工廠(Abstract Factory)定義
提供比工廠模式(Factory Pattern)高一級的接口。一般被用來返回多個工廠中的某一個工廠。
何時使用以及好處
創建了互相關聯和依靠的家族型對象,比如Kit
提供了產品的類庫,對外展示接口,而不是實施細節
將具體的類和它們的父類隔離開來
一個系統需要獨立於它的產品的創建,組成,和表達
需要強制實施一個限制
在表面之外的另一個選擇,可用來隱藏與平台有關的類
可以很容易的對一個系統和家族實施繼承
與此相關的設計模式包括,
工廠方法(Factory Method),通常用抽象工廠的方法來實施
單例(Singleton),通常用抽象工廠的方法來實施
原型(Prototype),通常用抽象工廠的方法來實施
外觀(Facade),通常與抽象工廠一同使用,來提供一個可以創建實施類的接口
代碼舉例
假設你需要一個程序在不同的地方來顯示數據,比如從本地和遠程的數據庫。在與數據打交道之前,你需要建立一個和數據庫的連接。在這個case裡,你有兩個選擇,本地數據庫和遠程數據庫。你可以使用一個抽象工廠的模式來設計這個接口:
class DataInfo {}
interface Local {
DataInfo[] loadDB(String filename);
}
interface Remote extends Local{
void connect2WWW(String url);
}
class LocalMode implements Local {
public DataInfo[] loadDB(String name) {
System.out.print("Load from a local database ");
return null;
}
}
class RemoteMode implements Remote {
public void connect2WWW(String url) {
System.out.println("Connect to a remote site ");
}
//下面是對loadDB方法的另一種實施 public DataInfo[] loadDB(String name) {
System.out.println("Load from a remote database ");
return null;
}
}
//下面就是抽象工廠了interface ConnectionFactory {
Local getLocalConnection();
Remote getRemoteConnection();
}
class DataManager implements ConnectionFactory {
boolean local = false;
DataInfo[] data;
//...
public Local getLocalConnection() {
return new LocalMode();
}
public Remote getRemoteConnection() {
return new RemoteMode();
}
public void loadData() {
if(local){
Local conn = getLocalConnection();
data = conn.loadDB("db.db");
}else {
Remote conn = getRemoteConnection();
conn.connect2WWW("www.some.where.com");
data = conn.loadDB("db.db");
}
}
// work on data
public void setConnection(boolean b) {
local = b;
}
}
//用以下測試方法來測試上述的類class Test {
public static void main(String[] args) {
DataManager dm = new DataManager();
DataInfo[] di = null;
String dbFileName = "db.db"$$
if (args.length == 1) {
//assume local is set to true
dm.setConnection(true);
LocalMode lm = (LocalMode)dm.getLocalConnection();
di = lm.loadDB(dbFileName);
} else {
//Note: dm.local = false is default setting
RemoteMode rm = (RemoteMode)dm.getRemoteConnection();
rm.connect2WWW("www.javacamp.org/db/");
di = rm.loadDB(dbFileName);
}
//以下就可以僅僅使用一套方法來處理用上述方法加載的數據
//Like di.find(), di.search() etc.
//從此,不需再為數據庫的連接而擔心
}
}
下面是從命令行調用Test類而進行測試的情況,注意,因參數的不同,而出現的不同運行結果。
C:> java Test
Connect to a remote site
Load from a remote database
C:> java Test local
Load from a local database
C: Comma
這樣的設計一般會用在在Sun公司開發人員的認證考試中。如果你可以從不同的地方加載數據,你只需在connection工廠接口中加入一個方法,在合適的位置實施它,而不需對其他程序結構有絲毫的改變。