當(dāng)你在程序代碼中看到new關(guān)鍵字時(shí),代表你看到了一個(gè)具體類被實(shí)例化,創(chuàng)建了一個(gè)新的實(shí)例化對象。這里用的是實(shí)現(xiàn),而不是接口。我們知道,代碼綁定具體類而非接口會導(dǎo)致代碼不易擴(kuò)展,更脆弱,更缺乏彈性。
假設(shè)有一款抽象汽車產(chǎn)品Car,派生出奔馳車(BenzCar),寶馬車(BMwCar),路虎車(LandRoverCar),如下圖:

作為司機(jī),要開其中一個(gè)品牌的車,例如奔馳,最直接的做法就是創(chuàng)建一個(gè)BenzCar對象,如下:
BenzCar benzCar = new BenzCar();
benzCar.drive();
如果司機(jī)想換成寶馬汽車開,就必須要修改代碼,如下:
BMWCar bmwCar = new BMWCar();
bmwCar.drive();
這也就意味著,任何時(shí)候司機(jī)換車輛開,必須要修改客戶端的代碼。
一種稍微好的方式是通過外部傳遞汽車的名稱,來決定創(chuàng)建哪一種汽車,并向上轉(zhuǎn)型成父類Car:
String carName = "Benz";
Car car = null;
if(carName.equals("Benz")) {
car = new BenzCar();
} else if(carName.equals("BMW")) {
car = new BMWCar();
} else if (carName.equals("LandRover")) {
car = new LandRoverCar();
}
然而,我們在設(shè)計(jì)代碼的時(shí)候,總是希望改動(dòng)代碼越少越好,最好是不改。當(dāng)我們的汽車產(chǎn)品新增一款新品牌時(shí),上面的代碼就需要增加else if條件滿足新的品牌對象創(chuàng)建,這就造成我們的客戶端代碼總是需要跟著修改。
為了減少代碼的修改,我們的設(shè)計(jì)原則是把變化的部分單獨(dú)抽離出來,減少代碼的改動(dòng)。到此簡單工廠模式的模型就出來了,把一直需要變化而創(chuàng)建對象的代碼抽離成一個(gè)工廠類,并對外提供一個(gè)類似getInstance方法來獲取創(chuàng)建的對象,代碼如下:
public class SimpleFactory {
public Car getCar(String name) {
Car car = null;
if(name.equals("Benz")) {
car = new BenzCar();
} else if(name.equals("BMW")) {
car = new BMWCar();
} else if (name.equals("LandRover")) {
car = new LandRoverCar();
}
return car;
}
}
于是,我們的客戶端代碼改寫如下:
public class TestMain {
public static void main(String[] args) {
Car car = SimpleFactory.getCar("Benz");
car.drive();
car = SimpleFactory.getCar("BMW");
car.drive();
}
}
如果未來增加了汽車品牌,也只需要修改簡單工廠類,而無須修改客戶端代碼,對上層代碼透明。
簡單工廠模式定義
簡單工廠模式的類圖如下,其實(shí)嚴(yán)格來說它并不是一個(gè)設(shè)計(jì)模式,反而像一種編程習(xí)慣。

Client : 通過組合SimpleFactory和產(chǎn)品父類Car的方式提供客戶功能。
SimpleFactory:內(nèi)部保持了一個(gè)產(chǎn)品父類的引用Car,也是通過組合的方式來實(shí)現(xiàn)具體產(chǎn)品的創(chuàng)建。
Car及其子類:一個(gè)產(chǎn)品家族,從父類派生出不同的同類產(chǎn)品。
簡單工廠模式缺點(diǎn)
簡單工廠模式并不滿足開閉原則:對擴(kuò)展開發(fā),對修改關(guān)閉。產(chǎn)品增加時(shí),仍然需要修改工廠類支持更多的同類產(chǎn)品。
簡單工廠的典型應(yīng)用
簡單工廠模式在JDK中最典型的應(yīng)用就是JDBC了??梢园殃P(guān)系型數(shù)據(jù)庫認(rèn)為是一種抽象產(chǎn)品,各廠商提供的具體關(guān)系型數(shù)據(jù)庫(MySQL,PostgreSQL,Oracle)則是具體產(chǎn)品。DriverManager是工廠類。應(yīng)用程序通過JDBC接口使用關(guān)系型數(shù)據(jù)庫時(shí),并不需要關(guān)心具體使用的是哪種數(shù)據(jù)庫,而直接使用DriverManager的靜態(tài)方法去得到該數(shù)據(jù)庫的Connection,具體是哪個(gè)數(shù)據(jù)庫由Class.forName加載數(shù)據(jù)庫驅(qū)動(dòng)類的全路徑名決定。
public class JDBC {
private static final Logger LOG = LoggerFactory.getLogger(JDBC.class);
public static void main(String[] args) {
Connection conn = null;
try {
Class.forName("org.apache.hive.jdbc.HiveDriver");
conn = DriverManager.getConnection("jdbc:hive2://127.0.0.1:10000/default");
PreparedStatement ps = conn.prepareStatement("select count(*) from test.test");
ps.execute();
} catch (SQLException ex) {
LOG.warn("Execute query failed", ex);
} catch(ClassNotFoundException e) {
LOG.warn("Load Hive driver failed", e);
} finally {
if(conn != null ){
try {
conn.close();
} catch (SQLException e) {
// NO-OPT
}
}
}
}
}
推薦閱讀
設(shè)計(jì)模式(一)策略模式
設(shè)計(jì)模式(二)觀察者模式
設(shè)計(jì)模式(三)裝飾器模式
