本篇文章介紹一種設計模式——工廠模式。工廠模式是用來封裝對象的創(chuàng)建恨樟,減少應用程序和具體類之間的依賴半醉,促進松耦合。根據(jù)工廠模式的應用特性劝术,一共分為三種子模式:簡單工廠模式缩多,工廠方法模式和抽象工廠模式。本篇文章主要介紹簡單工廠模式养晋。本篇文章內(nèi)容參考《JAVA與模式》之簡單工廠模式衬吆。
一、簡單工廠模式簡介
1.定義
簡單工廠模式(Simple Factory Pattern):又稱為靜態(tài)工廠方法(Static Factory Method)模式绳泉,它屬于類創(chuàng)建型模式逊抡。在簡單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創(chuàng)建其他類的實例冒嫡,被創(chuàng)建的實例通常都具有共同的父類拇勃。
2.使用動機
考慮一個簡單的軟件應用場景:一個軟件系統(tǒng)可以提供多個外觀不同的按鈕(如圓形按鈕、矩形按鈕孝凌、菱形按鈕等)方咆, 這些按鈕都源自同一個基類,不過在繼承基類后不同的子類修改了部分屬性從而使得它們可以呈現(xiàn)不同的外觀蟀架。
如果我們希望在使用這些按鈕時瓣赂,不需要知道這些具體按鈕類的名字,只需要知道表示該按鈕類的一個參數(shù)片拍,并提供一個調(diào)用方便的方法煌集,把該參數(shù)傳入方法即可返回一個相應的按鈕對象,此時捌省,就可以使用簡單工廠模式苫纤。
二、簡單工廠模式結(jié)構(gòu)
1.模式結(jié)構(gòu)
簡單工廠模式包含如下角色:
●Factory:工廠角色
工廠角色負責實現(xiàn)創(chuàng)建所有實例的內(nèi)部邏輯
●Product:抽象產(chǎn)品角色
抽象產(chǎn)品角色是所創(chuàng)建的所有對象的父類所禀,負責描述所有實例所共有的公共接口
●ConcreteProduct:具體產(chǎn)品角色
具體產(chǎn)品角色是創(chuàng)建目標方面,所有創(chuàng)建的對象都充當這個角色的某個具體類的實例。
2.時序圖
①先調(diào)用工廠類中的靜態(tài)方法createProduct()
②根據(jù)傳入產(chǎn)品類型參數(shù)色徘,獲得具體的產(chǎn)品對象
③返回產(chǎn)品對象并使用
三、簡單工廠的使用實例
以登錄功能來說操禀,假如應用系統(tǒng)需要支持多種登錄方式如:口令認證褂策、域認證(口令認證通常是去數(shù)據(jù)庫中驗證用戶,而域認證則是需要到微軟的域中驗證用戶)颓屑。那么自然的做法就是建立一個各種登錄方式都適用的接口斤寂,如下圖所示:
抽象產(chǎn)品Login
public interface Login {
//登錄驗證
public boolean verify(String name , String password);
}
具體產(chǎn)品DomainLogin
public class DomainLogin implements Login {
@Override
public boolean verify(String name, String password) {
// TODO Auto-generated method stub
/**
* 業(yè)務邏輯
*/
return true;
}
}
**具體產(chǎn)品PasswordLogin **
public class PasswordLogin implements Login {
@Override
public boolean verify(String name, String password) {
// TODO Auto-generated method stub
/**
* 業(yè)務邏輯
*/
return true;
}
}
工廠類LoginManager
根據(jù)調(diào)用者不同的要求,創(chuàng)建出不同的登錄對象并返回揪惦。而如果碰到不合法的要求遍搞,會返回一個Runtime異常。
public class LoginManager {
public static Login factory(String type){
if(type.equals("password")){
return new PasswordLogin();
}else if(type.equals("passcode")){
return new DomainLogin();
}else{
/**
* 這里拋出一個自定義異常會更恰當
*/
throw new RuntimeException("沒有找到登錄類型");
}
}
}
測試調(diào)用
public class Test {
public static void main(String[] args) {
String loginType = "password";
String name = "name";
String password = "password";
Login login = LoginManager.factory(loginType);
boolean bool = login.verify(name, password);
if (bool) {
/**
* 業(yè)務邏輯
*/
} else {
/**
* 業(yè)務邏輯
*/
}
}
}
假如不使用簡單工廠模式則驗證登錄Servlet代碼如下:
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
String loginType = "password";
String name = "name";
String password = "password";
//處理口令認證
if(loginType.equals("password")){
PasswordLogin passwordLogin = new PasswordLogin();
boolean bool = passwordLogin.verify(name, password);
if (bool) {
/**
* 業(yè)務邏輯
*/
} else {
/**
* 業(yè)務邏輯
*/
}
}
//處理域認證
else if(loginType.equals("passcode")){
DomainLogin domainLogin = new DomainLogin();
boolean bool = domainLogin.verify(name, password);
if (bool) {
/**
* 業(yè)務邏輯
*/
} else {
/**
* 業(yè)務邏輯
*/
}
}else{
/**
* 業(yè)務邏輯
*/
}
}
}
可以看到非常麻煩器腋,代碼重復很多溪猿,而且不利于擴展維護。
四纫塌、簡單工廠模式優(yōu)缺點
優(yōu)點:
通過使用工廠類诊县,外界不再需要關心如何創(chuàng)造各種具體的產(chǎn)品,只要提供一個產(chǎn)品的名稱作為參數(shù)傳給工廠措左,就可以直接得到一個想要的產(chǎn)品對象依痊,并且可以按照接口規(guī)范來調(diào)用產(chǎn)品對象的所有功能(方法)。
構(gòu)造容易怎披,邏輯簡單胸嘁。
缺點:
1.簡單工廠模式中的if else判斷非常多瓶摆,完全是Hard Code,如果有一個新產(chǎn)品要加進來性宏,就要同時添加一個新產(chǎn)品類赏壹,并且必須修改工廠類,再加入一個 else if 分支才可以衔沼, 這樣就違背了 “開放-關閉原則”中的對修改關閉的準則了蝌借。當系統(tǒng)中的具體產(chǎn)品類不斷增多時候,就要不斷的修改工廠類指蚁,對系統(tǒng)的維護和擴展不利菩佑。
2.一個工廠類中集合了所有的類的實例創(chuàng)建邏輯,違反了高內(nèi)聚的責任分配原則凝化,將全部的創(chuàng)建邏輯都集中到了一個工廠類當中稍坯,所有的業(yè)務邏輯都在這個工廠類中實現(xiàn)。什么時候它不能工作了搓劫,整個系統(tǒng)都會受到影響瞧哟。因此一般只在很簡單的情況下應用,比如當工廠類負責創(chuàng)建的對象比較少時枪向。
3.簡單工廠模式由于使用了靜態(tài)工廠方法勤揩,造成工廠角色無法形成基于繼承的等級結(jié)構(gòu)。
適用環(huán)境
在以下情況下可以使用簡單工廠模式:
工廠類負責創(chuàng)建的對象比較少:由于創(chuàng)建的對象較少秘蛔,不會造成工廠方法中的業(yè)務邏輯太過復雜陨亡。
客戶端只知道傳入工廠類的參數(shù),對于如何創(chuàng)建對象不關心:客戶端既不需要關心創(chuàng)建細節(jié)深员,甚至連類名都不需要記住负蠕,只需要知道類型所對應的參數(shù)。
五倦畅、簡單工廠模式在Java中的應用
①JDK類庫中廣泛使用了簡單工廠模式遮糖,如工具類java.text.DateFormat,它用于格式化一個本地日期或者時間叠赐。
public final static DateFormat getDateInstance();
public final static DateFormat getDateInstance(int style);
public final static DateFormat getDateInstance(int style,Locale
locale);
②Java加密技術(shù)
獲取不同加密算法的密鑰生成器:
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
創(chuàng)建密碼器:
Cipher cp=Cipher.getInstance("DESede");