工廠模式-23種設計模式系列

什麼是工廠模式?

定義: 工廠模式又稱爲創建模式,它是建對象的一種最佳方式。工廠模式的本質就是用工廠方法代替new操作創建一種實例化對象的方式。一句話中總結就是方便創建 同種類型接口產品 的 複雜對象

核心:

  • 實現了創建者和調用者分離
  • 實例對象不用new,而用工廠方法代替
  • 將選擇實現類,創建對象統一管理和控制。從而將調用者和我們的實現類解耦

三種模式:

  • 簡單工廠模式:用來生產同一等級結構的任意商品(對於增加新的商品,需要修改已有代碼)
  • 工廠方法模式:用來生產同一等級結構中固定商品(支持增加任意產品)
  • 抽象工廠模式:圍繞一個超級工廠創建其他工廠,該超級工廠又城其他工廠的工廠。

應用實例: 1、您需要一輛汽車,可以直接從工廠裏面提貨,而不用去管這輛汽車是怎麼做出來的,以及這個汽車裏面的具體實現。 2、Hibernate 換數據庫只需換方言和驅動就可以。

優點: 1、一個調用者想創建一個對象,只要知道其名稱就可以了。 2、擴展性高,如果想增加一個產品,只要擴展一個工廠類就可以。 3、屏蔽產品的具體實現,調用者只關心產品的接口。

缺點: 每次增加一個產品時,都需要增加一個具體類和對象實現工廠,使得系統中類的個數成倍增加,在一定程度上增加了系統的複雜度,同時也增加了系統具體類的依賴。這並不是什麼好事。

使用場景: 1、日誌記錄器:記錄可能記錄到本地硬盤、系統事件、遠程服務器等,用戶可以選擇記錄日誌到什麼地方。 2、數據庫訪問,當用戶不知道最後系統採用哪一類數據庫,以及數據庫可能有變化時。 3、設計一個連接服務器的框架,需要三個協議,“POP3”、“IMAP”、“HTTP”,可以把這三個作爲產品類,共同實現一個接口。

注意事項: 作爲一種創建類模式,在任何需要生成複雜對象的地方,都可以使用工廠方法模式。有一點需要注意的地方就是複雜對象適合使用工廠模式,而簡單對象,特別是只需要通過 new 就可以完成創建的對象,無需使用工廠模式。如果使用工廠模式,就需要引入一個工廠類,會增加系統的複雜度。

簡單工廠模式

在介紹簡單工程模式前,我們現需要回顧一下OOP的七大原則,因爲工廠模式也是需要符合這七大原則的。

OOP七大原則:

  • 開閉原則:一個軟件的實體應該對擴展開放,對修改關閉
  • 依賴倒轉原則:要針對接口編程,不要針對實現編程
  • 迪米特法則:直與你直接的朋友通信,避免和陌生人通信

然後我們寫一個車的接口

public interface Car {
    void Name();
}

再寫兩個車的實現類

public class Wuling implements Car{
    @Override
    public void Name() {
        System.out.println("五菱宏光!");
    }
}
public class TesLa implements Car{
    @Override
    public void Name() {
        System.out.println("特斯拉!");
    }
}

再過去我們想要得到Wuling和Tesla的對象,最常用的方法就是直接new。

//消費者(測試類)
public class Consumer {
    public static void main(String[] args) {
        Car car1=new Wuling();
        Car car2=new TesLa();

        car1.Name();car2.Name();
    }
}

在這裏插入圖片描述
但是上面這種操作,我們需要知道接口和所有的實現類才能得到對象。就好像你想要一臺車,然後你自己造(new)了一輛車,但是現實生活中,如果你想要的一臺車,你會怎麼做?去工廠買,你不需要知道工廠怎麼造車。

工廠模式的核心就是實例對象不用new,而用工廠方法代替,我們用代碼實現一個車工廠

public class CarFactory {
    public static Car getCar(String car){
        if (car.equals("五菱宏光"))
            return new Wuling();
        else if (car.equals("特斯拉"))
            return new TesLa();
        else
            return null;
    }
}

這樣我們的消費者需要車,直接去工廠買就可以了,不需要自己造了。需要什麼車(Car),直接給車工廠(CarFactory)傳一個字符串參數就可以了,不需要知道里面的細節,甚至不需要知道實現類(符合OOP七大原則之依賴倒轉原則:要針對接口編程,不要針對實現編程)。

//用工廠實現
Car car1 = CarFactory.getCar("五菱宏光");
Car car2 = CarFactory.getCar("特斯拉");

在這裏插入圖片描述

問題來了,如果我們需要增加一個實現類呢?

public class DaZhong implements Car{
    @Override
    public void Name() {
        System.out.println("大衆!");
    }
}

我們需要修改我們的車工廠(CarFactory),在裏面加一個判斷

public class CarFactory {
    public static Car getCar(String car){
        if (car.equals("五菱宏光"))
            return new Wuling();
        else if (car.equals("特斯拉"))
            return new TesLa();
        else if (car.equals("大衆"))
            return new DaZhong();
        else
            return null;
    }
}

這樣就違反了OOP七大原則(開閉原則:一個軟件的實體應該對擴展開放,對修改關閉),所以簡單工廠模式是有一點小問題的,不能動態的增加實現類,無法在不修改車工廠代碼的前提下增加實現類,而且簡單工廠裏面車工廠的方法都是靜態的,因此簡單工廠模式又叫靜態工廠模式

但是事實上,看源碼可知,我們使用的最多的還是簡單工廠模式,因爲如果想做滿足開閉原則,你將會付出很大代價,代碼量將會增大很多,就比如下面的 工廠方法模式

工廠方法模式

工廠方法模式是思路很簡單,就是再寫一個車工廠的接口。

public interface CarFactory {
    Car getCar();
}

讓每個車有自己的工廠,每個工廠再實現車工廠的接口。

//五菱車工廠
public class WulingFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Wuling();
    }
}
//特斯拉車工廠
public class TeslaFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new TesLa();
    }
}

消費者如果想要車,只需去對應的車工廠去買車就可以了。要五菱去五菱車工廠,要特斯拉去特斯拉車工廠。

Car car1 = new WulingFactory().getCar();
Car car2 = new TeslaFactory().getCar();

在這裏插入圖片描述

這樣的話,即使再增加實現類,也只需要繼承車工廠的接口寫一個實現類即可,不需要修改車工廠的代碼了。和簡單工廠模式相比,簡單工廠模式只有一個車工廠類,所有的車都是在那裏面生成。工廠方法模式有多個車工廠,每個車都有自己的車工廠,但是所有的車工廠又都實現車工廠的接口,可以實現動態的增加車的實現類。

比如我們增加一個摩拜單車

public class Mobai implements Car{
    @Override
    public void Name() {
        System.out.println("摩拜單車!");
    }
}

只需要增加摩拜單車的車工廠,完全不需要改動其他類的代碼。

public class MobaiFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Mobai();
    }
}

消費者想要摩拜只需要去摩拜車工廠去買即可。

Car car3 = new MobaiFactory().getCar();

在這裏插入圖片描述

既然工廠方法模式可以動態的增加實現類還符合開閉原則,那爲什麼在源碼中簡單工程模式使用的更多呢?
在這裏插入圖片描述

簡單工廠模式和工廠方法模式進行對比

  • 結構複雜度上,simple(簡單工廠模式)更簡單
  • 代碼複雜度上,simple(簡單工廠模式)更簡單
  • 編程複雜度上,simple(簡單工廠模式)更簡單
  • 管理複雜度上,simple(簡單工廠模式)更簡單

所以根據設計原則我們應該選擇工廠方法模式,但是在實際開發中,簡單工程模式使用更多。(當然不是想偷懶)

抽象工廠模式

抽象工廠模式提供了一個 創建一系列相關或相互依賴對象的接口,無需指定他們具體的類。

在介紹抽象工廠之前,我們需要先清除一個概念,產品族和產品等級。就拿小米和華爲兩家公司生產的手機和路由器來舉例:小米手機和小米路由器都是小米的產品,屬於同一個產品族,而小米手機和華爲手機都是手機,屬於同一個產品等級。
在這裏插入圖片描述

我們先定義手機和路由器的接口

//手機產品接口
public interface IphoneProduct {
    void start();//開機
    void shutdown();//關機
    void callup();//打電話
    void sendSMS();//發信息
}
//路由器產品接口
public interface IRouterProduct {
    void start();//開機
    void shutdown();//關機
    void openWifi();//打開WiFi
    void setting();//設置
}

因爲小米和華爲都有自己的手機和路由器,所以需要分別實現他們的實現類。

//小米手機
public class XiaomiIphone implements IphoneProduct{
    @Override
    public void start() {
        System.out.println("開啓小米手機");
    }

    @Override
    public void shutdown() {
        System.out.println("關閉小米手機");
    }

    @Override
    public void callup() {
        System.out.println("用小米手機打電話");
    }

    @Override
    public void sendSMS() {
        System.out.println("用小米手機發信息");
    }
}
//華爲手機
public class HuaweiIphone implements IphoneProduct{
    @Override
    public void start() {
        System.out.println("開啓華爲手機");
    }

    @Override
    public void shutdown() {
        System.out.println("關閉華爲手機");
    }

    @Override
    public void callup() {
        System.out.println("用華爲手機打電話");
    }

    @Override
    public void sendSMS() {
        System.out.println("用華爲手機發信息");
    }
}
//小米路由器
public class XiaomiIRouter implements IRouterProduct{
    @Override
    public void start() {
        System.out.println("開啓小米路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("關閉小米路由器");
    }

    @Override
    public void openWifi() {
        System.out.println("打開小米WiFi");
    }

    @Override
    public void setting() {
        System.out.println("打開小米設置");
    }
}
//華爲路由器
public class HuaweiIRouter implements IRouterProduct{
    @Override
    public void start() {
        System.out.println("開啓華爲路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("關閉華爲路由器");
    }

    @Override
    public void openWifi() {
        System.out.println("打開華爲WiFi");
    }

    @Override
    public void setting() {
        System.out.println("打開華爲設置");
    }
}

現在產品都已經有了,我們需要去寫製造他們的工廠,小米工廠和華爲工廠。無論是小米還是華爲,工廠都是要生產手機和路由器的,所以我們可以先寫一個抽象工廠接口,小米和華爲都去繼承這個抽象工廠,不過小米生產小米的手機和路由器,華爲生產華爲的手機和路由器。

//抽象工廠
public interface IProductFactory {
    //生產手機
    IphoneProduct iphoneproduct();

    //生產路由器
    IRouterProduct irouterproduct();
}
//華爲工廠
public class HuaweiFactory implements IProductFactory{
    @Override
    public IphoneProduct iphoneproduct() {
        return new HuaweiIphone();//生產華爲手機
    }

    @Override
    public IRouterProduct irouterproduct() {
        return new HuaweiIRouter();//生產華爲路由器
    }
}
//小米工廠
public class XiaomiFactory implements IProductFactory{
    @Override
    public IphoneProduct iphoneproduct() {
        return new XiaomiIphone();//生產小米手機
    }

    @Override
    public IRouterProduct irouterproduct() {
        return new XiaomiIRouter();//生產小米路由器
    }
}

做完這些後,我們如果想要小米的產品就去小米工廠製造,如果想要華爲的產品就去華爲工廠製造。

 public static void main(String[] args) {
        System.out.println("======================小米系列產品======================");
        XiaomiFactory xiaomiFactory = new XiaomiFactory();
        IphoneProduct Xiaomiiphone = xiaomiFactory.iphoneproduct();
        IRouterProduct Xiaomiirouter = xiaomiFactory.irouterproduct();
        Xiaomiiphone.callup();Xiaomiirouter.openWifi();

        System.out.println("======================華爲系列產品======================");
        HuaweiFactory huaweiFactory = new HuaweiFactory();
        IphoneProduct Huaweiiphone = huaweiFactory.iphoneproduct();
        IRouterProduct Huaweiirouter = huaweiFactory.irouterproduct();
        Huaweiiphone.callup();Huaweiirouter.openWifi();
    }

在這裏插入圖片描述

最後的所有類的結構圖就是這個樣子,IProductFactory就是抽象工廠,圍繞着抽象工廠建造其他工廠,所以抽象工廠又稱爲工廠的工廠。
在這裏插入圖片描述

如果華爲和小米的產品族裏面還有筆記本,那我們就需要添加一個產品接口,再修改抽象工廠和實現的類,加入筆記本的製造方法。這樣就違反OOP的開閉原則(一個軟件的實體應該對擴展開放,對修改關閉),但是如果我們的產品是長期穩定不變的,就可以接受。和前兩種工廠 模式相比,抽象工廠把同一產品族放到了一起,一個工廠可以生產一個產品族。

總結

簡單工廠模式雖然違反了OOP七大原則,但是在實際中還是使用最多的。

工廠方法模式通過增加工廠在不違反OOP開閉原則的前提下實現動態擴展,但是代碼量大,編程和管理複雜反而沒有簡單工廠使用多。

抽象工廠模式圍繞一個抽象工廠去創建其他工廠,一個工廠可以生產一個產品族而不只是一個產品,但是不適合產品經常變動的情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章