設計模式 — 工廠模式

簡單工廠模式

  1. 簡單工廠模式是由一個工廠對象決定創建出哪一種產品類的實例

  2. 簡單工廠模式(靜態工廠模式):定義了一個創建對象的類,由這個類來封裝實例化對象的行為(程式碼)

  3. 在軟體開發中,當我們會用到大量的創建某種、某類或者某批對象時,就會使用到工廠模式.

注意:簡單工廠模式不是23中設計模式之一

  • 優點

    1. 工廠類包含必要的邏輯判斷,可以決定在什麼時候創建哪一個產品的實例。客戶端可以免除直接創建產品對象的職責,很方便的創建出相應的產品。工廠和產品的職責區分明確。

    2. 客戶端無需知道所創建具體產品的類名,只需知道參數即可。

    3. 也可以引入配置文件,在不修改客戶端程式碼的情況下更換和添加新的具體產品類。

  • 缺點

    1. 簡單工廠模式的工廠類單一,負責所有產品的創建,職責過重,一旦異常,整個系統將受影響。且工廠類程式碼會非常臃腫,違背高聚合原則。
    2. 使用簡單工廠模式會增加系統中類的個數(引入新的工廠類),增加系統的複雜度和理解難度
    3. 系統擴展困難,一旦增加新產品不得不修改工廠邏輯,在產品類型較多時,可能造成邏輯過於複雜
    4. 簡單工廠模式使用了 static 工廠方法,造成工廠角色無法形成基於繼承的等級結構。

應用場景

  • 對於產品種類相對較少的情況

  • 只知道傳入工廠類的參數,不關心如何創建對象的邏輯

案例

image

public interface Car {
    void name();
}

// 產品1
public class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}

// 產品1
public class WuLing 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 {
            return null;
        }
    }
    
}


public class Consumer {

    public static void main(String[] args){
        // 使用new創建對象
//        Car car1 = new Tesla();
//        Car car2 = new WuLing();

        // 通過簡單工廠模式創建
        Car car1 = CarFactory.getCar("五菱");
        Car car2 = CarFactory.getCar("特斯拉");

        car1.name();
        car2.name();

    }

}

工廠方法模式

用來生產同一等級結構中的固定產品(支援增加任意產品)

案例

image

public interface Car {

    void name();

}

// 工廠方法
public interface CarFactory {

    Car getCar();

}

public class BaoMa implements Car {
    @Override
    public void name() {
        System.out.println("寶馬");
    }
}
public class BaoMaFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new BaoMa();
    }
}

public class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("特斯拉");
    }
}
public class TeslaFactory implements CarFactory {
    @Override
    public Car getCar() {
        return new Tesla();
    }
}

public class WuLing implements Car {
    @Override
    public void name() {
        System.out.println("五菱");
    }
}
public class WuLingFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new WuLing();
    }
}

public class Consumer {

    public static void main(String[] args){

        // 通過工廠方法模式創建
        Car car1 = new WuLingFactory().getCar();
        Car car2 = new TeslaFactory().getCar();

        // 添加新的產品,不需要修改之前的程式碼
        Car car3 = new BaoMaFactory().getCar();

        car1.name();
        car2.name();
        car3.name();
    }

}

抽象工廠模式

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

image

適用場景

  • 客戶端(應用層)不依賴於產品類實例如何被創建、實現等細節

  • 強調一系列相關的產品對象(屬於同一產品族)一起使用創建對象需要大量的重複程式碼

  • 提供一個產品類的庫,所有的產品以同樣的介面出現,從而使得客戶端不依賴於具體的實現

優點

  • 具體產品在應用層的程式碼隔離,無需關心創建的細節
  • 將一個系列的產品統一到一起創建

缺點

  • 規定了所有可能被創建的產品集合,產品簇中擴展新的產品困難
  • 增加了系統的抽象性和理解難度

案例

image

public interface IPhoneProduct {

    void start();
    void shutdown();
    void callUp();
    void sendEmail();

}

public interface IRouterProduct {

    void start();
    void shutdown();
    void setWife();
    void setting();

}

// 抽象產品工廠
public interface ProductFactory {

    // 生產手機
    IPhoneProduct iphoneProduct();

    // 生產路由器
    IRouterProduct iRouterProduct();

}


public class XiaomiPhone 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 sendEmail() {
        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 sendEmail() {
        System.out.println("華為手機 發簡訊");
    }
}

public class XiaomiRouter implements IRouterProduct {
    @Override
    public void start() {
        System.out.println("小米路由器 開啟");
    }

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

    @Override
    public void setWife() {
        System.out.println("小米路由器 設置wife");
    }

    @Override
    public void setting() {
        System.out.println("小米路由器 相關設置");
    }
}

public class HuaweiRouter implements IRouterProduct {
    @Override
    public void start() {
        System.out.println("華為路由器 開啟");
    }

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

    @Override
    public void setWife() {
        System.out.println("華為路由器 設置wife");
    }

    @Override
    public void setting() {
        System.out.println("華為路由器 相關設置");
    }
}

public class XiaomiProductFactory implements ProductFactory {
    @Override
    public IPhoneProduct iphoneProduct() {
        return new XiaomiPhone();
    }

    @Override
    public IRouterProduct iRouterProduct() {
        return new XiaomiRouter();
    }
}

public class HuaweiProductFactory implements ProductFactory {
    @Override
    public IPhoneProduct iphoneProduct() {
        return new HuaweiiPhone();
    }

    @Override
    public IRouterProduct iRouterProduct() {
        return new HuaweiRouter();
    }
}


// 測試
public class Client {

    public static void main(String[] args){

        System.out.println("===== 小米系列產品 =====");
        XiaomiProductFactory xiaomiProductFactory = new XiaomiProductFactory();

        IPhoneProduct iPhoneProduct = xiaomiProductFactory.iphoneProduct();
        iPhoneProduct.start();
        iPhoneProduct.callUp();
        iPhoneProduct.sendEmail();

        IRouterProduct routerProduct = xiaomiProductFactory.iRouterProduct();
        routerProduct.start();
        routerProduct.setWife();
        routerProduct.setting();


        System.out.println("===== 華為系列產品 =====");
        HuaweiProductFactory huaweiProductFactory = new HuaweiProductFactory();

        IPhoneProduct iPhoneProduct2 = huaweiProductFactory.iphoneProduct();
        iPhoneProduct2.start();
        iPhoneProduct2.callUp();
        iPhoneProduct2.sendEmail();

        IRouterProduct routerProduct2 = huaweiProductFactory.iRouterProduct();
        routerProduct2.start();
        routerProduct2.setWife();
        routerProduct2.setting();


    }

}

image

小結

  • 簡單工廠模式(靜態工廠模式)
    雖然某種程度上不符合設計原則,但實際使用最多
  • 工廠方法模式
    不修改已有類的前提下,通過增加新的工廠類實現擴展。
  • 抽象工廠模式
    不可以增加產品,可以增加產品族