I walk very slowly, but I never walk backwards
工廠模式 - 簡單工廠模式
寂然
大家好~,我是寂然,本節課呢,我們來看下一個,工廠模式, 工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一,無論是實際應用還是面試都非常高頻和廣泛,話不多說,那我們開始啟程吧
案例引出 - 披薩訂購
那在聊工廠模式之前,我們現來看一個需求
有這樣一個披薩店的需求,披薩的種類很多(比如 GreekPizz、CheesePizz 等)
披薩的制作有 prepare,bake,cut,box 等
要求:完成披薩店訂購功能,便于披薩種類的擴充,便于維護
拿到這個需求,大家會怎麼實作呢?我們先不要想着工廠模式,用平時的思路,來完成下需求
解決方案一 - 一般實作方式
首先我們用一般常用的實作方式來解決,比如我們定義一個抽象類 pizza,因為我們 Pizza 的種類有很多,最容易想到的就是定義一個模闆,定義好 Pizza 的通用方法,比如,披薩的制作都需要 prepare,bake,cut,box 等方法,就可以定義到抽象類 Pizza裡面,具體種類的 Pizza 繼承抽象父類 Pizza ,就可以使用裡面的通用方法了,同時子類可以重寫方法,實作子類特有的業務邏輯,那根據上面的思路,對應的類圖如下圖所示

根據類圖,我們先把基礎的類定義出來,代碼示例如下圖所示
//抽象類接口 Pizza
public abstract class Pizza {
//定義一個屬性,披薩的名稱,并給定set方法
protected String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//認為不同的披薩,準備的原材料不同,是以定義成抽象方法
public abstract void prepare();
//烘焙方法
public void bake() {
System.out.println(name + "正在烘焙中");
}
//切割方法
public void cut() {
System.out.println(name + "正準備把披薩大卸八塊");
}
//打包方法
public void box() {
System.out.println(name + "将披薩打包給顧客");
}
}
//希臘披薩
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("準備希臘披薩的原材料");
}
}
//奶酪披薩
public class CheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("準備原材料 奶酪,芝士等");
}
}
OK,架構有了,當然我們還要完成訂購披薩的功能,建立 OrderPizza ,寫入訂購披薩的邏輯,同時我們希望擷取客戶想要訂購的披薩種類,進行訂購并制作,完整的實作代碼如下圖所示
//訂購披薩
public class OrderPizza {
//當然後面會進行改進,這是第一版的實作方式
//構造器
public OrderPizza(){
Pizza pizza = null;
String orderType; //訂購披薩的類型
while(true){
orderType = getType();//給定一個固定值先
if (orderType.equals("GreekPizza")){
pizza = new GreekPizza();
pizza.setName("GreekPizza");
}else if (orderType.equals("CheesePizza")){
pizza = new CheesePizza();
pizza.setName("CheesePizza");
}else{
break;
}
//輸出 Pizza 制作過程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}
//定義方法擷取客戶希望訂購的披薩種類
private String getType(){
System.out.println("你想訂購那個種類的Pizza呢?");
Scanner scanner = new Scanner(System.in);
String str = scanner.next();
return str;
}
}
//披薩商店,發出披薩訂購任務
public class PizzaStore {
public static void main(String[] args) {
new OrderPizza(); //構造器中完成相應功能
}
}
方案分析
OK,運作過後,首先保證實作了簡易的訂購披薩的需求,運作結果如下圖所示
那我們來談談這種實作方式的利弊
優點:符合我們一般的寫法,容易了解和接受
缺點:很明顯,違反了設計模式的開閉原則,對擴充開放,對修改關閉,即當我們給類增加新功能的時候,盡量不修改代碼,或者盡量少修改代碼,而上面的實作方式,假設我們新增 FruitPizza,我們需要做如下改動才能實作
//新定義水果披薩類
public class FruitPizza extends Pizza {
@Override
public void prepare() {
System.out.println("準備原材料 香蕉,鳳梨等");
}
}
//新增加判斷條件,如果是 FruitPizza 的處理邏輯
else if (orderType.equals("FruitPizza")){
pizza = new FruitPizza();
pizza.setName("FruitPizza");
}
改進思路
其實修改代碼是在允許範圍内的,但是如果我們在其他的地方也有建立 Pizza 的代碼,那就也需要修改,而建立 Pizza 的代碼,往往有多處,針對這個問題,我們可以有這樣一個思路:把建立 Pizza 對象的功能封裝到一個類中,這樣我們有新的 Pizza 種類的時候,隻需要修改該類即可,其他地方涉及到建立 Pizza 對象的代碼就不需要修改了,這種思路其實就是簡單工廠模式
基本介紹 - 簡單工廠模式
簡單工廠模式是屬于建立型模式,是工廠模式的一種,簡單工廠模式是由一個工廠對象決定建立出哪一種産品/類的執行個體,簡單工廠模式是工廠模式家族中最簡單實用的模式
簡單工廠模式:定義了一個建立對象的類,由這個類來封裝執行個體化對象的行為,在簡單工廠模式中,可以根據參數的不同傳回不同類的執行個體
在軟體開發中,當我們涉及到大量的建立某種或者某類對象時,就會使用到工廠模式,你隻需要使用工廠對象來需建立對象即可,具體的建立細節被工廠對象封裝起來
解決方案二 - 簡單工廠模式
那我們使用簡單工廠模式的思想,來對代碼進行重構,首先定義 SimpleFactory 類,讓該類作為工廠對象,來封裝執行個體化對象的行為,原來 訂購披薩類 OrderPizza 裡不再需要建立Pizza,調用SimpleFactory 類執行個體化對象的方法即可,代碼示例如下圖所示
// 案例示範 - 使用簡單工廠模式
// 簡單工廠類
public class SimpleFactory {
//執行個體化對象的方法
public Pizza createPizza(String orderType){
Pizza pizza = null;
if (orderType.equals("GreekPizza")){
pizza = new GreekPizza();
pizza.setName("GreekPizza");
}else if (orderType.equals("CheesePizza")){
pizza = new CheesePizza();
pizza.setName("CheesePizza");
}else if (orderType.equals("FruitPizza")){
pizza = new FruitPizza();
pizza.setName("FruitPizza");
}
return pizza;
}
}
上面我們按照簡單工廠模式的思想,把按需建立對象的行為封裝到 SimpleFactory 工廠類中,那現在 OrderPizza 中依賴 setSimpleFactory 即可,比如以成員屬性的形式,那擷取客戶想要訂購的披薩種類,進行訂購并制作的邏輯我們另外封裝一個方法,或者直接封裝在 simpleFactory 的 set() 方法裡 ,那根據這樣的想法,示例代碼如下
//建立簡單工廠類對象,給定set方法
SimpleFactory simpleFactory;
Pizza pizza = null; //初始化Pizza對象,初始值為null
//構造器裡調用 setSimpleFactory
public OrderPizza(SimpleFactory simpleFactory){
setSimpleFactory(simpleFactory);
}
public void setSimpleFactory(SimpleFactory simpleFactory) {
String ordertype = "";
this.simpleFactory = simpleFactory;
//可能是反複訂購
while (true){
ordertype = getType();//得到使用者想要的類型
pizza = this.simpleFactory.createPizza(ordertype);
if (pizza != null){ //表示訂購成功
//輸出 Pizza 制作過程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
System.out.println("披薩訂購失敗,沒有你要的Pizza");
break;
}
}
}
//披薩商店,發出披薩訂購任務
public class PizzaStore {
public static void main(String[] args) {
//new OrderPizza();
//使用簡單工廠模式
new OrderPizza(new SimpleFactory());
}
}
OK,上面我們用簡單工廠模式将代碼重構完畢,首先保訂購披薩的需求運作正常,運作結果如下圖所示
那我們來聊聊這種方式的好處或者說這種情況下,使用簡單工廠模式處理的好處,假設我們新增第四種Pizza,除了對該Pizza進行定義以外,隻需要在 SimpleFactory 工廠類,加一條 else if 判斷語句即可,其他地方不需要做改動,因為在簡單工廠模式中,工廠類負責封裝執行個體化對象的細節,是以業務邏輯中建立 Pizza 的代碼隻有這一處
簡單工廠模式也叫靜态工廠模式,舉個例子,還可以在 SimpleFactory 工廠類中把執行個體化對象的方法 createPizza 定義為靜态,這樣的話 OrderPizza 裡直接通過類名來調用 createPizza 即可,不需要通過構造器了,也是可以的,這裡就不做示範了
下節預告
OK,由于篇幅的限制,本節内容就先到這裡,下一節,我們接着來聊工廠模式,同樣是披薩訂購的案例,我們進行擴充,引出第二種要介紹的工廠方法模式,最後,希望大家在學習的過程中,能夠感覺到設計模式的有趣之處,高效而愉快的學習,那我們下期見~