工廠模式

在生活中,我們用的所有東西都是通過(guò)工廠生產(chǎn)出來(lái),比如:手機(jī),汽車,電腦等。在 面向?qū)ο蟮氖澜缋?,?duì)象也是可以通過(guò)工廠來(lái)創(chuàng)建的。今天我們就來(lái)談?wù)撘幌聞?chuàng)建型模式--工廠設(shè)計(jì)模式。

1. 案例背景

設(shè)計(jì)模式一般比較抽象,為了方便理解,我們首先來(lái)引用一個(gè)生活中的例子-- 消費(fèi)者去 汽車城或者4s 店 買汽車。這里有一下對(duì)象:1. 消費(fèi)者; 2. 汽車銷售方。 3. 汽車。

2. 不用設(shè)計(jì)模式

這里我們首先來(lái)分析 不使用 設(shè)計(jì)模式的情況下,代碼的實(shí)現(xiàn)方式

  • Car 接口

生活中 汽車銷售方一般是4s 店或者汽車經(jīng)銷商,一般都會(huì)銷售不同品牌或者型號(hào)的汽車,但是具體是啥汽車我們不知道,所以設(shè)計(jì)一個(gè)Car 接口,來(lái)抽象一下汽車的型號(hào)或者品牌

public interface Car {
    /**
     * 駕駛
汽車就一個(gè)方法,被被人駕駛
     */
    void drive();
}
  • 汽車

汽車接口設(shè)計(jì)好了,接下來(lái)我們就來(lái)設(shè)計(jì)一下具體的汽車,假設(shè) 是 寶馬和奧迪

public class BMWCar implements Car {
    @Override
    public void drive() {
        System.out.println("駕駛 BMW  !");
    }
}

public class AODICar implements Car {
    @Override
    public void drive() {
        System.out.println("  駕駛 奧迪  !");

    }
}
  • 汽車銷售對(duì)象

汽車有了,接下來(lái)我們來(lái)設(shè)計(jì) 汽車銷售對(duì)象。假設(shè)該能售賣 寶馬和奧迪

public class SaleCarStore {

    public Car sale(String carName) {
        Car car = null;
      if ("BMW".equals(carName)) {//寶馬汽車
          car = new BMWCar();
      }
      if ("AODI".equals(carName)) {// 奧迪汽車
          car = new AODICar();
      }
      return car;
    }
}

汽車銷售方就一個(gè)方法,就是 sale 汽車。我們沒有使用設(shè)計(jì)模式的情況下,一般是自己 new 對(duì)象。當(dāng)然實(shí)際生活中一般都是 汽車工廠生產(chǎn)好汽車,交給4s 店或者其他經(jīng)銷商來(lái)賣。后面我們?cè)賮?lái)分析使用 汽車工廠 的好處。

  • 消費(fèi)者

接下來(lái)我們只需要 設(shè)計(jì)一個(gè) 消費(fèi)者對(duì)象,通過(guò) 汽車消費(fèi)方去購(gòu)買汽車即可。

public class CarCustomer {
    private SaleCarStore saleCarStore ;
    CarCustomer(SaleCarStore saleCarStore) {//消費(fèi)者汽車售賣對(duì)象買車
        this.saleCarStore = saleCarStore;
    }

    public Car getCar(String carName) {
        Car car = saleCarStore.sale(carName);
        return car;
    }

    /**
     * 駕駛 買完車之后就 自己開車走了
     * @param car
     */
    public void drive(Car car) {
        car.drive();
    }
    public static void main(String[] args) {
        SaleCarStore saleCarStore = new SaleCarStore();
        CarCustomer carCustomer = new CarCustomer(saleCarStore );// 消費(fèi)者 通過(guò) SaleCarStore  對(duì)象買車
        Car bwm = carCustomer.getCar("BMW");// 假設(shè)購(gòu)買的是 寶馬
        carCustomer.drive(bwm);
    }

上面是我們?cè)跊]有使用 工廠設(shè)計(jì)模式下的代碼。消費(fèi)者成功的購(gòu)買到了汽車,并開走了。這時(shí)候,又有一個(gè)消費(fèi)者要來(lái)買汽車了,但是他嫌寶馬和奧迪都太貴了,要買五菱宏光,但是這時(shí)候 汽車銷售對(duì)象,沒有五菱宏光,但是上面的生意不可能不做吧,于是就連夜趕工 搞到了一臺(tái)。于是 SaleCarStore 對(duì)象就必須要修改:

public class SaleCarStore {

    public Car sale(String carName) {
        Car car = null;
      if ("BMW".equals(carName)) {//寶馬汽車
          car = new BMWCar();
      }
      if ("AODI".equals(carName)) {// 奧迪汽車
          car = new AODICar();
      }
      // add 
      if ("WLHG".equals(carName)) {// 五菱宏光
          car = new WLHGCar();
      }
      return car;
    }
}

----- 購(gòu)買
public static void main(String[] args) {
        SaleCarStore car4sStore = new SaleCarStore();
        CarCustomer carCustomer = new CarCustomer(car4sStore);
        Car bwm = carCustomer.getCar("WLHG");
        carCustomer.drive(bwm);
    }

好了,錢賺到了。生意越來(lái)越好,接下來(lái),買各種各樣的車的人都有,比如 思域啊,邁銳寶XL 啊,奧迪A4L 啊等等。那么我們這時(shí)候如果在原來(lái)的基礎(chǔ)上 滿足消費(fèi)者的需求就要不斷 的 添加 如下類似的代碼:

// add .......
      if ("WLHG".equals(carName)) {// 五菱宏光
          car = new WLHGCar();
      }
// add .......

這時(shí)候,老板就發(fā)現(xiàn),自己不能再這樣搞下去了,雖然錢賺到了,自己卻累的要死。于是,就想到一個(gè)主意:顧客要來(lái)買車,就先下個(gè)單子,拿到這個(gè)單子以后,去聯(lián)系 汽車生產(chǎn)廠商,然他們?nèi)ドa(chǎn)汽車,自己中間賺差價(jià)就好了。于是,代碼就可以改成下面的樣子:

  • 汽車工廠--簡(jiǎn)單工廠
public class SimpleCarFactory {

    public Car createCar(String carName) {
        Car car = null;
        if ("BMW".equals(carName)) {//寶馬汽車
            car = new BMWCar();
        }
        if ("AODI".equals(carName)) {// 奧迪汽車
            car = new AODICar();
        }
        if ("WLHG".equals(carName)) {// 五菱宏光
            car = new WLHGCar();
        }

        return car;
    }
}
----- SaleCarStore 
public class SaleCarStore {

    private SimpleCarFactory simpleCarFactory;
    SaleCarStore(SimpleCarFactory simpleCarFactory) {
        this.simpleCarFactory = simpleCarFactory;
    }

    public Car sale(String carName) {
//        Car car = null;
////      if ("BMW".equals(carName)) {//寶馬汽車
////          car = new BMWCar();
////      }
////      if ("AODI".equals(carName)) {// 奧迪汽車
////          car = new AODICar();
////      }
////      // add
////      if ("WLHG".equals(carName)) {// 五菱宏光
////          car = new WLHGCar();
////      }
        // 簡(jiǎn)單工廠創(chuàng)建Car 對(duì)象
        Car car = simpleCarFactory.createCar(carName);
        return car;
    }
}
---- CarCustomer#main
 public static void main(String[] args) {
// 簡(jiǎn)單工廠
        SimpleCarFactory simpleCarFactory = new SimpleCarFactory();
        SaleCarStore saleCarStore = new SaleCarStore(simpleCarFactory);
        CarCustomer carCustomer = new CarCustomer(saleCarStore);
        Car bwm = carCustomer.getCar("WLHG");
        carCustomer.drive(bwm);
    }

好了,現(xiàn)在 汽車經(jīng)銷商老板 輕松了,不管顧客需要什么樣的汽車,都可以交給 SimpleCarFactory 工廠來(lái)生產(chǎn)了。

注意:簡(jiǎn)單工廠模式原本是不屬于常用23中設(shè)計(jì)模式中的,在《Head First》中有解釋,上面的案例也是從 這本書中演變來(lái)的,書中是 披薩 案例。

  • 工廠方法

承接上一個(gè)案例,雖然顧客對(duì)汽車的需求加大,各種汽車都要滿足,于是 SimpleCarFactory 汽車工廠 必須擴(kuò)展自己的 createCar 方法,隨著工廠規(guī)模的發(fā)展出現(xiàn)了以下代碼:

 public Car createCar(String carName) {
        Car car = null;
        if ("BMW".equals(carName)) {//寶馬汽車
            car = new BMWCar();
        }
        if ("AODI".equals(carName)) {// 奧迪汽車
            car = new AODICar();
        }
        if ("WLHG".equals(carName)) {// 五菱宏光
            car = new WLHGCar();
        }
       // add if()........
       // add if()........
       // add if()........
        return car;
    }

我們發(fā)現(xiàn),要是無(wú)限添加 if ,createCar 方法會(huì)變得難以維護(hù)。作為工廠老板,就想了一個(gè)辦法,把 createCar ()拆開,分成不同的生產(chǎn)小組,生產(chǎn)各自的汽車,于是 代碼就變成了這樣:

public class CarFactoryMethod  {

    //生產(chǎn)寶馬
    public BMWCar createBMWCar() {
        return new BMWCar();
    }

    // 生產(chǎn)奧迪
    public AODICar createAODICar() {
        return new AODICar();
    }

    //生產(chǎn)五菱宏光
    public WLHGCar createWLHGCar() {
        return new WLHGCar();
    }
}

上面這個(gè)模式就被叫做 工廠方法。如果,現(xiàn)在新增一個(gè)汽車,只需要添加一個(gè) 方法,來(lái)創(chuàng)建即可。

  • 抽象工廠

隨著工廠的發(fā)展,寶馬車出現(xiàn)了不同的車系,如X1,X6 等,奧迪出現(xiàn)了 A3,A4L,A6L等,于是,寶馬和奧迪工廠就獨(dú)立出來(lái)了,單獨(dú)生產(chǎn)這幾種車系。

public class BMWFactoryMethod {

    public BMWCarX1 X1() {
        return new BMWCarX1();
    }

    public BMWCarX5 X5() {
        return new BMWCarX5();
    }
}

------- 奧迪車系
public class AODIFactoryMethod {

    public AODICarA3 aodiCarA3() {
        return new AODICarA3();
    }
    
    public AODICarA4L aodiCarA4L() {
        return new AODICarA4L();
    }
}

首先,要說(shuō)明一個(gè)問題,抽象工廠,不是對(duì)代碼的抽象,也就說(shuō) 在代碼里面 我們不需要將工廠 用 abstract 修飾,抽象工廠,是從 《Head First》中翻譯過(guò)來(lái)的,抽象工廠 是對(duì) 工廠方法的延伸,抽象工廠可以生產(chǎn) 一系列相關(guān)的產(chǎn)品,比如 寶馬系列,奧迪系列。這里就是 國(guó)內(nèi)經(jīng)常有人說(shuō)的 產(chǎn)品到 產(chǎn)品族的概念。注意,這里為了描述簡(jiǎn)單,并沒有 抽取接口,重要的是 編程思想, 我們從 工廠方法,生產(chǎn)單個(gè)汽車產(chǎn)品,到 擴(kuò)展到一個(gè)工廠可以生產(chǎn) 一系列相關(guān)的系列汽車產(chǎn)品,也就是 從 工廠方法 擴(kuò)展到了 抽象工廠。那么抽象 就應(yīng)該是對(duì) 事物擴(kuò)展的抽象了,而不是具體對(duì) 代碼的抽象,并不強(qiáng)制你對(duì)代碼進(jìn)行抽象。比如,擴(kuò)展寶馬車系,對(duì)不可預(yù)見的車系進(jìn)行抽象,因?yàn)槲也⒉恢?,下一個(gè)寶馬車系是啥,但是一旦確定了,就可以直接在工廠中添加方法創(chuàng)建即可,所以,這里的抽象應(yīng)該是對(duì)事物的抽象。

在我們明白了產(chǎn)品到 產(chǎn)品系列的概念后,可以對(duì)抽象工廠 進(jìn)行接口設(shè)計(jì)。

  • CarFactory
/**
 * car 工廠定義
 */
public interface CarFactory {

    Car createCar(String type);
}

----- car 
public class BMWCarX1 implements Car {

    public BMWCarX1() {
        System.out.println("X1");
    }

    @Override
    public void drive() {
        System.out.println("drive X1");
    }
}

public class BMWCarX5 implements Car {

    public BMWCarX5() {
        System.out.println("X5");
    }

    @Override
    public void drive() {
        System.out.println("drive X5");
    }
}

------- BMWCarFactoryMethod 抽象工廠
public class BMWCarFactoryMethod implements CarFactory {
    @Override
    public Car createCar(String type) {
        switch (type) {
            case "X1":
                return bmwCarX1();
            case "X5":
                return bmwCarX5();
        }
        return null;
    }

    private BMWCarX1 bmwCarX1() {
        return new BMWCarX1();
    }
    private BMWCarX5 bmwCarX5() {
        return new BMWCarX5();
    }
}

到這里我們就分析了 工廠模式中的 簡(jiǎn)單工廠,工廠方法和抽象工廠的設(shè)計(jì)思想。我們可以發(fā)現(xiàn)一個(gè)問題,工廠模式是不符合 開閉原則的,但是比較符合單一職責(zé)原則,工廠模式實(shí)現(xiàn)方式可以有多中,不必糾結(jié)固定的實(shí)現(xiàn)方式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 通過(guò)面向?qū)ο蟮姆庋b,繼承和多態(tài)來(lái)降低程序的耦合度。下面就讓我們來(lái)深入學(xué)習(xí)這個(gè)模式。 工廠模式:客戶類和工廠類分開。...
    linbj閱讀 1,125評(píng)論 0 0
  • 0、序 在上一篇文章《工廠方法模式》中,我們定義了奧迪工廠AudiFactory 生產(chǎn)出來(lái)的就是奧迪汽車和 奔馳工...
    YotrolZ閱讀 934評(píng)論 0 1
  • 為了防止被“殺”了祭天,學(xué)點(diǎn)設(shè)計(jì)模式,并總結(jié)下還是有必要的。 一:模式理解 工廠模式的作用是新建對(duì)象。 工廠模式的...
    阿菜的博客閱讀 1,166評(píng)論 0 19
  • 工廠模式概述 工廠模式是設(shè)計(jì)模式的一種,從功能上來(lái)說(shuō),它的主要作用是創(chuàng)建對(duì)象。細(xì)分一下,有三種不同類型的工廠模式,...
    flionel閱讀 775評(píng)論 5 3
  • 等待 也許,你等了很久 也許,你不再期待 但也許,你等的人正在來(lái)的路上 夜 在路上 與你相遇在熟悉的街...
    Msint趙客閱讀 159評(píng)論 0 0

友情鏈接更多精彩內(nèi)容