個人部落格原文
建立型模式:工廠方法
簡介
姓名:工廠方法
英文名:Factory method Pattern
價值觀:擴充套件是我的專屬
個人介紹:
Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses. (定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。)
(來自《設計模式之禪》)
你要的故事
還記得上一篇 單例模式 中的故事麼?小明開著汽車去旅遊、去學校、去聚會。這一次還是延續小明的故事,一個故事能講 2 個設計模式,不容易呀。。。(每次想故事都想破腦袋,每一篇文章至少有 3 個故事從腦子裡閃過,但最終留下的只有一個適合,為了就是能比較清晰簡單的說明設計模式中的關鍵要點。)
簡單工廠
小明家裡以前不算很富裕,但是還是有一個不錯的車庫,什麼汽車、摩托車、自行車啥的都放在這個車庫裡。小明每次要出去,都會到車庫裡面挑合適的車出發。比如,小明最近期末考試了,騎摩托車去學校考試,考完試之後,小明就準備去旅遊,這次決定自駕遊,開著自己家的小汽車去。這個場景我們用程式碼描述下。
public class SimpleFactoryTest {
public static void main(String[] args) {
XiaoMing xiaoMing = new XiaoMing();
// 小明騎摩托車去學校
IVehicle motorcycle = GarageFactory.getVehicle("motorcycle");
xiaoMing.goToSchool(motorcycle);
// 小明開汽車去旅遊
IVehicle car = GarageFactory.getVehicle("car");
xiaoMing.travel(car);
}
}
/**
* 車庫
*/
class GarageFactory {
public static IVehicle getVehicle(String type) {
if ("car".equals(type)) {
return new Car();
} else if ("motorcycle".equals(type)) {
return new Motorcycle();
}
throw new IllegalArgumentException("請輸入車型別");
}
}
/**
* 交通工具
*/
interface IVehicle {
void run();
}
/**
* 汽車
*/
class Car implements IVehicle {
@Override
public void run() {
System.out.println("開汽車去。。。。");
}
}
/**
* 摩托車
*/
class Motorcycle implements IVehicle {
@Override
public void run() {
System.out.println("騎摩托車去。。。。");
}
}
class XiaoMing {
public void goToSchool(IVehicle vehicle) {
System.out.println("小明去學校");
vehicle.run();
}
public void travel(IVehicle vehicle) {
System.out.println("小明去旅遊");
vehicle.run();
}
}
上面程式碼看懂了麼? 小明家裡有一個車庫 GarageFactory,裡面放著汽車 Car 和摩托車 Motorcycle,小明要出去的時候,就到車庫選擇車,通過傳遞引數給 GarageFactory.getVehicle(),指明要什麼車,然後小明就騎著車出發了。
這個程式碼真正的術語叫:簡單工廠模式(Simple Factory Pattern),也叫做靜態工廠模式。它是工廠方法中的一個實現方式,從字面理解就可以知道,它是最簡單的工廠方法實現方式。它有一點點小缺陷,就是擴充套件性不夠好,在上面程式碼中,小明只能騎摩托車或者開汽車,如果小明要騎單車出去呢?勢必得在 GarageFactory 中新增 if 是自行車的邏輯。這違反了哪條規則了?是不是那個允許擴充套件,拒絕修改的開閉原則?
不是說簡單工廠這種實現方式不好,而是擴充套件性不夠,在平時的開發中,簡單工廠模式也用得不少。在這個小明家裡車不多的情況下,用一個車庫也是合適的。
工廠方法
小明老爸近幾年賺了不少,車迷的兩父子一直買車,家裡的車越來越多,這時候,他們決定多建幾個車庫,按車型別放置。比如,有一個汽車庫,一個摩托車庫。這時候小明要開汽車就去汽車庫,要騎摩托車就去摩托車庫。程式碼實現如下。
public class FactoryMethodTest {
public static void main(String[] args) {
XiaoMing xiaoMing = new XiaoMing();
// 小明騎摩托車去學校
VehicleGarage motorcycleGarage = new MotorcycleGarage();
IVehicle motorcycle = motorcycleGarage.getVehicle();
xiaoMing.goToSchool(motorcycle);
// 小明開汽車去旅遊
VehicleGarage carGarage = new CarGarage();
IVehicle car = carGarage.getVehicle();
xiaoMing.travel(car);
}
}
interface VehicleGarage {
IVehicle getVehicle();
}
/**
* 汽車車庫
*/
class CarGarage implements VehicleGarage {
@Override
public IVehicle getVehicle() {
return new Car();
}
}
/**
* 摩托車車庫
*/
class MotorcycleGarage implements VehicleGarage {
@Override
public IVehicle getVehicle() {
return new Motorcycle();
}
}
上面程式碼重用了簡單工廠實現方式的交通介面以及摩托車和汽車的實現類。程式碼中有 2 個車庫,一個是汽車車庫 CarGarage,一個是摩托車庫 MotorcycleGarage。如果小明要騎自行車,只需要建一個自行車車庫,完全不用去修改汽車車庫或者摩托車車庫,就非常符合開閉原則,擴充套件性大大的提高。
總結
工廠方法模式可以說在你能想到的開源框架原始碼中必定會使用的一個設計模式,因為開源框架很重要一點就是要有擴充套件性,而工廠方法模式恰恰具有可擴充套件性。弄懂了工廠方法模式,以後看開原始碼就很得心應手啦。
參考資料:《大話設計模式》、《Java設計模式》、《設計模式之禪》、《研磨設計模式》、《Head First 設計模式》
程式碼連結:Factory method Pattern
希望文章對您有所幫助,設計模式系列會持續更新,感興趣的同學可以關注公眾號 LieBrother,第一時間獲取文章推送閱讀,也可以一起交流,交個朋友。