1. 程式人生 > 其它 >設計模式の工廠模式

設計模式の工廠模式

簡單工廠模式

  • 簡單工廠模式是屬於建立型模式,是工廠模式的一種。簡單工廠模式是由一個工廠物件決定創建出哪一種產品類的例項。

  • 簡單工廠模式是工廠模式家族中最簡單實用的模式

  • 簡單工廠模式:定義了一個建立物件的類,由這個類來封裝例項化物件的行為(程式碼)

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

  • 手機制造頂層介面

public interface Phone {
    void make();
}
  • 小米制造商

public class XiaoMiPhone implements Phone {
    @Override
    
public void make() { System.out.println("製造了一臺小米手機"); } }
  • 華為製造商

public class HuaWeiPhone implements  Phone{
    @Override
    public void make() {
        System.out.println("製造了一臺華為手機");
    }
}
  • 手機制造代工廠(富士康)

public class PhoneFactory {
    public Phone makePhone(String phoneType){
        
if ("xiaomi".equals(phoneType)){ return new XiaoMiPhone(); }else if ("huawei".equals(phoneType)){ return new HuaWeiPhone(); } return null; } }
  • 使用者需求方

public class TestMain {
    public static void main(String[] args) {
        PhoneFactory phoneFactory 
= new PhoneFactory(); Phone xiaomi = phoneFactory.makePhone("xiaomi"); xiaomi.make(); Phone huawei = phoneFactory.makePhone("huawei"); huawei.make(); } }
  • 類圖如下所示

簡單工廠模式的缺點就在於

通過上面製造手機的列子可以看出,此時我們的工廠只能生產華為和小米兩款手機

  • 如果想要生辰更多的品牌手機,那就的在工廠中加條件適配

  • 沒增加一個手機品牌,就要去修改工廠的原始碼,這種操作不符合開閉原則

  • 但是我們可以對其進行優化,使其符合開閉原則

//    public Phone makePhone(String phoneType){
//        if ("xiaomi".equals(phoneType)){
//            return new XiaoMiPhone();
//        }else if ("huawei".equals(phoneType)){
//            return new HuaWeiPhone();
//        }
//        return null;
//    }
public Phone makePhoneOptimize(Class <? extends Phone> clazz){
        if (null != clazz){
            try {
                return clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

然後使用者對應的使用方式也跟著改變一下

//        PhoneFactory phoneFactory = new PhoneFactory();
//        Phone xiaomi = phoneFactory.makePhone("xiaomi");
//        xiaomi.make();
//        Phone huawei = phoneFactory.makePhone("huawei");
//        huawei.make();
​
        PhoneFactory phoneFactory = new PhoneFactory();
        Phone xiaomi = phoneFactory.makePhoneOptimize(XiaoMiPhone.class);
        xiaomi.make();
        Phone huawei = phoneFactory.makePhoneOptimize(HuaWeiPhone.class);
        huawei.make();
​
    }

這樣,即使我們繼續擴充套件更多的品牌生產線,也可以不用動這一部分的原始碼了

簡單工廠模式在很多地方都在使用,

  • 比如日曆類Calendar.getInstance()方法

  • 或者logback中到 LoggerFactory 中有多個過載的方法 getLogger()

簡單工廠的缺點就是,工廠類的職責相對過重,不易於擴充套件過於複雜的產品結構

工廠方法模式

  • 和簡單工廠模式相比,工廠方法模式將生成具體產品的任務分發給具體的產品工廠,而不是由一個大工廠聚合生產

  • Phone 、XiaoMiPhone、HuaWeiPhone 類的不變

  • 新增抽象工廠類、小米工廠類、華為工廠類即可

  • 總工廠介面

public interface PhoneFactory {
    Phone makePhone();
}
  • 小米工廠類

public class XiaoMiFactory implements PhoneFactory { 
  @Override
  public Phone makePhone() {
  // 這裡的方式是:;若生產何種產品完全由工廠決定,則這裡不應該傳入控制生產的引數。
  // 如果消費者知道自己想要什麼產品,可以入參,用引數來區別對待生產不同的產品。像簡單工廠模式一一致
  return new XiaoMiPhone();
  }
}
  • 華為工廠類

public class HuaWeiFactory implements PhoneFactory { 
  @Override
  public Phone makePhone() {
  // 這裡的方式是:;若生產何種產品完全由工廠決定,則這裡不應該傳入控制生產的引數。
  // 如果消費者知道自己想要什麼產品,可以入參,用引數來區別對待生產不同的產品。像簡單工廠模式一一致
  return new HuaWeiPhone();
  }
}
  • 使用者需求方

public class TestMain {
    public static void main(String[] args) {
        PhoneFactory  xiaoMiFactory = new XiaoMiFactory();
        PhoneFactory  huaWeiFactory = new HuaWeiFactory();
        Phone xiaomi = xiaoMiFactory.makePhone();
        Phone huawei = huaWeiFactory.makePhone();
        xiaomi.make();
        huawei.make();
    }
}
  • 類圖如下所示

工廠方法模式主要解決的是產品的擴充套件問題

  • 在簡單工程模式中,最後我們使用反射的方式實現開閉原則

  • 但是如果沒餓過課程的建立邏輯有區別的話,工廠的職責就會越加繁重,不利於維護

  • 根據單一職責原則,我們可以將職能進行劃分

    • 最大的工廠只負責約束管理

    • 其下允許動態建立其他幹實事的小工廠

    • 就比如富士康只負責談需求,接單,產品驗收

    • 但其下的子工廠或者找個外包工廠(自由擴充套件)來幹活

  • 工廠方法模式和簡單工廠的區別就在於

    • 簡單工廠只有一個工廠,負責產品的建立和銷售

    • 工廠方法模式,有一個最大的工廠負責制定規章制度,旗下有很多專一的小工廠來負責生產和銷售

抽象工廠模式

  • 定義了一個 interface 用於建立相關或有依賴關係的物件簇,而無需指明具體的類

  • 抽象工廠模式可以將簡單工廠模式和工廠方法模式進行整合。

  • 從設計層面看,抽象工廠模式就是對簡單工廠模式的改進(或者稱為進一步的抽象)

  • 將工廠抽象成兩層,AbsFactory(抽象工廠) 和 具體實現的工廠子類。程式設計師可以根據建立物件型別使用對應的工廠子類。這樣將單個的簡單工廠類變成了工廠簇,更利於程式碼的維護和擴充套件。

  • 上面的工廠模式都是在圍繞手機在生產,如果這個時候,我們新增一個PC領域進去該如何玩呢?

  • 手機制造頂級介面

public interface Phone {
    void make();
}
  • 小米手機制造商

public class XiaoMiPhone implements Phone {
    @Override
    public void make() {
        System.out.println("製造了一臺小米手機");
    }
}
  • 華為手機制造商

public class HuaWeiPhone implements Phone {
    @Override
    public void make() {
        System.out.println("製造了一臺華為手機");
    }
}
  • 筆記本製造頂級介面

public interface PC {
    void make();
}
  • 小米筆記本製造商

public class XiaoMiPC implements PC{
    @Override
    public void make() {
        System.out.println("生產了一臺小米筆記本");
    }
}
  • 華為筆記本製造商

public class HuaWeiPC implements PC{
    @Override
    public void make() {
        System.out.println("生產了一臺華為筆記本");
    }
}
  • 代工廠頂級介面

public interface AbstractFactory {
    Phone makePhone();
    PC makePC();
}
  • 小米代工廠製造介面

public class XiaoMiFactory implements AbstractFactory {
    @Override
    public Phone makePhone() {
        // 這裡的方式是:;若生產何種產品完全由工廠決定,則這裡不應該傳入控制生產的引數。
        // 如果消費者知道自己想要什麼產品,可以入參,用引數來區別對待生產不同的產品。想簡答工廠模式一一致
        return new XiaoMiPhone();
    }
​
    @Override
    public PC makePC() {
        // 這裡的方式是:;若生產何種產品完全由工廠決定,則這裡不應該傳入控制生產的引數。
        // 如果消費者知道自己想要什麼產品,可以入參,用引數來區別對待生產不同的產品。想簡答工廠模式一一致
        return new XiaoMiPC();
    }
}
  • 華為代工廠製造介面

public class HuaWeiFactory implements AbstractFactory {
    @Override
    public Phone makePhone() {
        // 這裡的方式是:;若生產何種產品完全由工廠決定,則這裡不應該傳入控制生產的引數。
        // 如果消費者知道自己想要什麼產品,可以入參,用引數來區別對待生產不同的產品。想簡答工廠模式一一致
        return new HuaWeiPhone();
    }
​
    @Override
    public PC makePC() {
        // 這裡的方式是:;若生產何種產品完全由工廠決定,則這裡不應該傳入控制生產的引數。
        // 如果消費者知道自己想要什麼產品,可以入參,用引數來區別對待生產不同的產品。想簡答工廠模式一一致
        return new HuaWeiPC();
    }
}
  • 需求方

public class TestMain {
    public static void main(String[] args) {
        AbstractFactory xiaoMiFactory = new XiaoMiFactory();
        AbstractFactory huaWeiFactory = new HuaWeiFactory();
        Phone xiaomi = xiaoMiFactory.makePhone();
        PC xiaomiPC = xiaoMiFactory.makePC();
        Phone huawei = huaWeiFactory.makePhone();
        PC huaweiPC = huaWeiFactory.makePC();
        xiaomi.make();
        xiaomiPC.make();
        huawei.make();
        huaweiPC.make();
    }
}
  • 類圖如下所示

  • 此時,如果我們覺得手機和筆記本都已經玩膩了,想進軍造車行業

    • 定義造成頂級介面

    • 定義造車品牌實現介面,比如小鵬汽車,蔚來汽車等

    • 此時增加代工頂級介面一個允許生產汽車的行為,並寫一個汽車代工廠即可工廠

    • 擴充套件性就大大的增加了

抽象工廠非常完美清晰地描述這樣一層複雜的關係

  • 小米公司可以生產手機和膝上型電腦

  • 華為公司可以生成手機和膝上型電腦

  • 如果此時我們還想繼續追加他的功能職責,比如生產無人機

    • 這個時候就要定義一個無人機的頂級介面

    • 然後小米和華為都要再定義一個無人機的實現類

    • 然後再在代工廠頂級介面中新增一個生產無人機的方法(開閉原則被破壞)

    • 最後小米和華為的Factory,重寫代工廠頂級介面中方法,實現無人機的生產(開閉原則被破壞)

    • 使用的時候,如上方使用程式碼差異無二

  • 因此抽象工程模式也是有很大缺點的,維護難度加大,理解難度加大

    • 擴充套件時 - > 代工廠頂級介面需要維護

    • 擴充套件時 - > 代工廠頂級介面的實現工廠也要維護實現對應方法

  • 但是在實際應用中,我們新增一個功能職責的週期是很長的,只要不是頻繁新增,這種設計模式仍然適合我們

  • 抽象工廠模式在Spring中的應用是最為廣泛的一種設計模式

工廠模式小結

  • 工廠模式的意義

    • 將例項化物件的程式碼提取出來,放到一個類中統一管理維護,達到和主專案的依賴關係的解耦。從而提高專案的擴充套件和維護性。

  • 三種工廠模式 (簡單工廠模式、工廠方法模式、抽象工廠模式)

  • 設計模式的依賴抽象原則

    • 建立物件例項時,不要直接 new 類, 而是把這個 new 類的動作放在一個工廠的方法中,並返回

    • 不要讓類繼承具體類,而是繼承抽象類或者是實現 interface(介面)

    • Ø 不要覆蓋基類中已經實現的方法。

.