做系統(tǒng)設(shè)計(jì)的時(shí)候有時(shí)會(huì)碰到一些無法在父類(或者接口)中抽取通用行為的特性,遇到這種情況就可以采用StringConfigure模式,這個(gè)模式我取的名字,不知道是否已經(jīng)有先人做了總結(jié),如果哪位朋友知道這種模式的正確名稱,希望不吝賜教。
以JDBC中取得數(shù)據(jù)庫連接為例,我們可以抽象出數(shù)據(jù)庫的一些公共行為,比如連接數(shù)據(jù)庫都要求提供用戶名和密碼,因此在JDBC中提供設(shè)定連接的用戶名和密碼的方法。但是另外的一些行為則不一定是所有數(shù)據(jù)庫都具備的,比如對(duì)于網(wǎng)絡(luò)型數(shù)據(jù)庫才需要指定網(wǎng)絡(luò)地址,而文件型數(shù)據(jù)庫則不需要,再比如在MySQL中需要指定字符集,而其他數(shù)據(jù)庫則不一定需要。如果為了照顧這些特性,為JDBC提供setHostIP、setDBFilePath、setCharSet等方法的話無疑會(huì)使得接口變得復(fù)雜,會(huì)出現(xiàn)很多用不到的方法,并且這些方法也無法覆蓋所有未來可能出現(xiàn)的情況,比如某個(gè)數(shù)據(jù)庫又增加了允許用戶定制連接超時(shí)的方法,那么JDBC也要為他提供相應(yīng)的setTimeOut方法。為了解決這個(gè)問題,JDBC提出了連接字符串的概念,這樣各個(gè)數(shù)據(jù)庫的JDBC驅(qū)動(dòng)只要規(guī)定好連接字符串的格式即可,用戶把所有的配置信息寫到連接字符串中,如果用戶修改為其他數(shù)據(jù)庫的話只需修改連接字符串即可,不用修改其他的調(diào)用。
使用StringConfigure模式的好處是使得系統(tǒng)中的個(gè)性化配置在一個(gè)參數(shù)中完成,這樣保證系統(tǒng)的不同模塊的行為的一致性,缺點(diǎn)是配置字符串的格式要由各個(gè)實(shí)現(xiàn)模塊來規(guī)定,各個(gè)不同實(shí)現(xiàn)模塊的格式不一致,造成了一定的學(xué)習(xí)成本,而且無法在開發(fā)期發(fā)現(xiàn)配置字符串的問題。
這里再來講一個(gè)StringConfigure模式的應(yīng)用的例子。現(xiàn)在我們要開發(fā)一套對(duì)IC卡讀寫器的類庫,應(yīng)用開發(fā)人員只要調(diào)用不同的IC卡讀寫子類即可實(shí)現(xiàn)操作不同的IC卡讀寫器。各種不同的IC卡讀寫器有兩個(gè)共同的抽象行為:讀卡和寫卡,即readCard和writeCard,但是各個(gè)不同的讀卡器還有自己的特性,比如有的讀卡器需要指定采用ISO格式還是IBM格式來讀寫磁卡,有的讀卡器需要指定讀寫操作的分隔符,這些特性不是各個(gè)讀寫器共有的,因此我們采用StringConfigure模式進(jìn)行設(shè)計(jì),開發(fā)如下的接口:
interface IICCarder
{
public void writeCard(String data);
public String readCard();
public void configure(String configStr);
}
比如需要指定讀寫格式的讀寫器就可以如下實(shí)現(xiàn):
class SomeCarder implements IICarder
{
private FormatEnum format;
public void writeCard(String data)
{
if(format==FormatEnum.IBM)
{
.........
}
else...........
}
public String readCard()
{.............
}
public void configure(String configStr)
{
if(configStr.equls("IBM"))
{
format=FormatEnum.IBM
}
else if(configStr.equls("ISO"))
{
format=FormatEnum.ISO
}
}
}
開發(fā)人員使用的時(shí)候只要如下調(diào)用
IICarder c = new SomeCarder();
c.configure("IBM");
print c.readCard();
如果采用配置文件的話更可以把配置參數(shù)寫到配置文件中,這樣就可以避免修改代碼。