設計模式 --並不簡單的工廠模式

前言

上幾節課咱們講了單例模式,今天咱們再來說另一個比較經常使用的建立型模式:工廠模式(Factory Design Pattern)。設計模式

通常狀況下,工廠模式分爲三種更加細分的類型:簡單工廠、工廠方法和抽象工廠。實際上,這三種咱們最經常使用得是第一種簡單工廠和工廠方法模式。而抽象工廠的原理稍微複雜點,在實際的項目中相對也不經常使用。因此,咱們今天主要講解的重點是前兩種工廠模式。ide

簡單工廠(Simple Factory)

// 建立抽象產品類,定義具體產品得公共接口
abstract class Product{
    public abstract void Show();
}
// 建立具體產品類(繼承抽象產品類),定義生產的具體產品

//具體產品類A
class  ProductA extends  Product{
    @Override
    public void Show() {
        System.out.println("生產出了產品A");
    }
}

//具體產品類B
class  ProductB extends  Product{

    @Override
    public void Show() {
        System.out.println("生產出了產品C");
    }
}
// 建立工廠類,經過建立靜態方法從而根據傳入不一樣參數建立不一樣具體產品類的實例
class  Factory {
    public static Product Manufacture(String ProductName){
//工廠類裏用switch語句控制生產哪一種商品;
//使用者只須要調用工廠類的靜態方法就能夠實現產品類的實例化。
        switch (ProductName){
            case "A":
                return new ProductA();
            case "B":
                return new ProductB();
            default:
                return null;

        }
    }
}

能夠看到,對於上面得簡單工廠的實現方法,若是咱們要添加新的Product,那勢必要改動到 Factory 的代碼,那這是否是違反開閉原則呢?實際上,若是不是須要頻繁地添加新的 Product,只是偶爾修改一下Factory代碼,稍微不符合開閉原則,也是徹底能夠接受的。函數

除此以外,在 Factory 有一組 if 分支判斷邏輯,是否是應該用多態或其餘設計模式來替代呢?實際上,若是 if 分支並非不少,代碼中有 if 分支也是徹底能夠接受的。應用多態或設計模式來替代 if 分支判斷邏輯,也並非沒有任何缺點的,它雖然提升了代碼的擴展性,更加符合開閉原則,但也增長了類的個數,犧牲了代碼的可讀性。學習

總結一下,儘管簡單工廠模式的代碼實現中,有多處 if 分支判斷邏輯,違背開閉原則,但權衡擴展性和可讀性,這樣的代碼實如今大多數狀況下(好比,不須要頻繁地添加 Product,也沒有太多的 Product)是沒有問題的。設計

工廠方法(Factory Method)

//建立抽象工廠類,定義具體工廠的公共接口
abstract class IFactory{
    public abstract Product Manufacture();
}

//工廠A類 - 生產A類產品
class  FactoryA extends IFactory{
    @Override
    public Product Manufacture() {
        return new ProductA();
    }
}

//工廠B類 - 生產B類產品
class  FactoryB extends IFactory{
    @Override
    public Product Manufacture() {
        return new ProductB();
    }
}

實際上,這就是工廠方法模式的典型代碼實現。這樣當咱們新增一種 Product 的時候,只須要新增一個實現了 IFactory 接口的 Factory 類便可。因此,工廠方法模式比起簡單工廠模式更加符合開閉原則。code

看似很完美了,可是這裏仍是有一些小問題,簡單工廠只是把麻煩的if判斷從工廠類,移交到了使用者手裏,怎麼說呢?來看下面這段代碼對象

//生產工做流程
public class FactoryPattern {
    public static void main(String[] args){
        //客戶要產品A
        Product mFactoryA = load("A");
        mFactoryA.Manufacture().Show();

        //客戶要產品B
        Product mFactoryB = load("A");
        mFactoryB.Manufacture().Show();
    }
    
    

  public IFactory load(String factoryType) {

    IFactory factory = null;
    if ("A".equalsIgnoreCase(factoryType)) {
      factory = new FactoryA();
    } else if ("B".equalsIgnoreCase(factoryType)) {
      factory = new FactoryB();
    } else {
      throw new InvalidRuleConfigException("factoryType is not supported: " + factoryType);
    }

    return factory;
  }
}

從上面的代碼實現來看,工廠類對象的建立邏輯又耦合進了 load() 函數中,跟咱們最初的代碼版本很是類似。假如咱們的業務需求是,根據讀取的配置文件來建立相應的Product,其實不論是簡單工廠模式仍是方法工廠模式,上訴的if判斷都沒法消滅掉(因此在 GoF 的《設計模式》一書中,它將簡單工廠模式看做是工廠方法模式的一種特例繼承

抽象工廠(Abstract Factory)

講完了簡單工廠、工廠方法,咱們再來看抽象工廠模式。抽象工廠模式的應用場景比較特殊,沒有前兩種經常使用,不是咱們學習的重點,咱們來簡單瞭解一下就好了。接口

咱們這裏有一個需求場景,有一個工廠,他主要生產容器和模具。對於容器和模具下面又分不少種類。以下:工作流

// 容器
ContainerProductA 
ContainerProductB

//模具
MouldProductA
MouldProductB

針對這種特殊的場景,若是仍是繼續用工廠方法來實現的話,咱們要針對每一個產品 都編寫一個工廠類,也就是要編寫 4 個工廠類。若是咱們將來還須要增長了其餘類型的生產產品(好比 杯子),那就要再對應地增長 2 個工廠類。而咱們知道,過多的類也會讓系統難維護。這個問題該怎麼解決呢?

抽象工廠就是針對這種很是特殊的場景而誕生的。咱們可讓一個工廠負責建立多個不一樣類型的對象(容器、模具、杯子 等),而不是隻建立一種 Product 對象。這樣就能夠有效地減小工廠類的個數。具體的代碼實現以下所示:

//建立抽象工廠類,定義具體工廠的公共接口
abstract class Factory{
   public abstract Product ManufactureContainer();
    public abstract Product ManufactureMould();
}
//建立抽象產品族類 ,定義具體產品的公共接口;
abstract class AbstractProduct{
    public abstract void Show();
}
//容器產品抽象類
abstract class ContainerProduct extends AbstractProduct{
    @Override
    public abstract void Show();
}

//模具產品抽象類
abstract class MouldProduct extends AbstractProduct{
    @Override
    public abstract void Show();
}
//容器產品A類
class ContainerProductA extends ContainerProduct{
    @Override
    public void Show() {
        System.out.println("生產出了容器產品A");
    }
}

//容器產品B類
class ContainerProductB extends ContainerProduct{
    @Override
    public void Show() {
        System.out.println("生產出了容器產品B");
    }
}

//模具產品A類
class MouldProductA extends MouldProduct{

    @Override
    public void Show() {
        System.out.println("生產出了模具產品A");
    }
}

//模具產品B類
class MouldProductB extends MouldProduct{

    @Override
    public void Show() {
        System.out.println("生產出了模具產品B");
    }
}
//A廠 - 生產模具+容器產品
class FactoryA extends Factory{

    @Override
    public Product ManufactureContainer() {
        return new ContainerProductA();
    }

    @Override
    public Product ManufactureMould() {
        return new MouldProductA();
    }
}

//B廠 - 生產模具+容器產品
class FactoryB extends Factory{

    @Override
    public Product ManufactureContainer() {
        return new ContainerProductB();
    }

    @Override
    public Product ManufactureMould() {
        return new MouldProductB();
    }
}

總結

咱們來一塊總結回顧一下,這裏的三種工廠模式中,簡單工廠和工廠方法比較經常使用,抽象工廠的應用場景比較特殊,因此不多用到,其實瞭解一下就能夠了。

當建立邏輯比較複雜,是一個「大工程」的時候,咱們就考慮使用工廠模式,封裝對象的建立過程,將對象的建立和使用相分離。何爲建立邏輯比較複雜呢?

  • 代碼中若是存在 if-else分支判斷,動態地根據不一樣的類型建立不一樣的對象。針對這種狀況,咱們就考慮使用工廠模式,將這一大坨if-else建立對象的代碼抽離出來,放到工廠類中。
  • 還有一種狀況,就是對象的建立十分複雜,咱們也可使用工廠類的方式來屏蔽對象的建立細節(建造者模式也是解決該類問題),在這種狀況下,咱們也能夠考慮使用工廠模式,將對象的建立過程封裝到工廠類中

對於第一種狀況,當每一個對象的建立邏輯都比較簡單的時候,推薦使用簡單工廠模式,將多個對象的建立邏輯放到一個工廠類中。

當每一個對象的建立邏輯都比較複雜的時候,爲了不設計一個過於龐大的簡單工廠類,推薦使用工廠方法模式,將建立邏輯拆分得更細,每一個對象的建立邏輯獨立到各自的工廠類中。

仍是那句話,不要爲了使用設計模式而用設計模式,設計模式都是在相應的使用場景下而誕生的。

相關文章
相關標籤/搜索