定義:
由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例.
類型:
創(chuàng)建型(creational), 但不屬于GOF23種設(shè)計(jì)模式.
適用場(chǎng)景:
1, 負(fù)責(zé)創(chuàng)建的對(duì)象比較少.
2, 應(yīng)用層只知道傳入工廠類的參數(shù),對(duì)于如何創(chuàng)建對(duì)象并不關(guān)心.
優(yōu)點(diǎn):
實(shí)現(xiàn)簡單
工廠模式實(shí)例:
創(chuàng)建一個(gè)生產(chǎn)獲取數(shù)據(jù)庫連接的工廠
先抽象出產(chǎn)品接口
public interface DBConnection {
String getConnection();
}
實(shí)現(xiàn)獲取Mysql和Oracle連接:
public class MysqlConnection implements DBConnection{
@Override
public String getConnection() {
return "Mysql Connection";
}
}
public class OracleConnection implements DBConnection{
@Override
public String getConnection() {
return "Oracle Connection";
}
}
簡單工廠模式實(shí)現(xiàn)連接工廠:
public class DBConnectionFactory {
public DBConnection getConnection(String name){
if("mysql".equalsIgnoreCase(name)){
return new MysqlConnection();
}else if("oracle".equalsIgnoreCase(name)){
return new OracleConnection();
}else {
throw new IllegalArgumentException("no such connection");
}
}
}
測(cè)試:
public class Test1 {
public static void main(String[] args) {
DBConnectionFactory factory = new DBConnectionFactory();
DBConnection connection = factory.getConnection("mysql");
System.out.println(connection.getConnection());
// TODO sth
}
}
客戶端只需傳入需要的數(shù)據(jù)庫名稱即可獲取到想要的數(shù)據(jù)庫連接而無需關(guān)心工廠類實(shí)現(xiàn)細(xì)節(jié), 如果客戶端需要更改數(shù)據(jù)庫連接, 只需要修改mysql為oracle即可,非常方便.
DBConnectionFactory 中的 getConnection 方法可以用靜態(tài)方法實(shí)現(xiàn),這樣客戶端就無需創(chuàng)建一個(gè)工廠對(duì)象出來.
但是這種方式也有缺點(diǎn), 如果我需要新增一個(gè)數(shù)據(jù)庫如sql server, 那么久必須修改getConnection 方法, 這明顯違背了開閉原則.
使用反射解決上述問題.
public class DBConnectionFactory2 {
public static <T extends DBConnection> DBConnection getConnection(Class<T> clazz){
try {
return (DBConnection) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
使用方法
public class Test2 {
public static void main(String[] args) {
DBConnection connection = DBConnectionFactory2.getConnection(MysqlConnection.class);
System.out.println(connection.getConnection());
// TODO sth
}
}
這樣就避免了新增實(shí)現(xiàn)類之后需要修改工廠類的尷尬.
JDK中的單例模式:
如 java.util.Calendar#createCalendar
其中
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
根據(jù)參數(shù)的不同返回不同的實(shí)現(xiàn)