「補課」進行時:設計模式(2)——通過一個超級汽車工廠來了解工廠模式

極客挖掘機發表於2020-10-22

1. 超級汽車工廠

汽車相信大家都不陌生,我們現在最常用的交通工具得益於在賓士在 1885 年研製的第一輛「三輪車」,就是下面這個傢伙:

今天我來試一下使用程式通過汽車工廠來造汽車。

1.1 定義一輛汽車

public interface Car {
    void name();
    void drive();
}

身為一輛汽車,首先要有自己的名字,其次是要能開,有了這兩個東西,基本上就能叫一輛汽車了。

1.2 定義一輛特斯拉、一輛賓士、一輛奧迪

public class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("我是特斯拉!!!");
    }

    @Override
    public void drive() {
        System.out.println("我是特斯拉,速度賊快!!!");
    }
}

public class Benz implements Car {
    @Override
    public void name() {
        System.out.println("我是賓士!!!");
    }

    @Override
    public void drive() {
        System.out.println("我是賓士,內飾豪華!!!");
    }
}

public class Audi implements Car {
    @Override
    public void name() {
        System.out.println("我是奧迪!!!");
    }

    @Override
    public void drive() {
        System.out.println("我是奧迪,科技感十足!!!");
    }
}

這裡定義了三輛汽車,分別實現了他們的父親的兩個方法。

1.3 定義抽象汽車工廠

身為一個超級汽車工廠,當然是要能造汽車,我們建立汽車的時候,肯定是希望直接告訴工廠,我要造一輛特斯拉還是造一輛奧迪。

如果是使用特斯拉或者是奧迪作為輸入引數,那麼建立的方法我們就需要分別寫 3 個了,在 Java 中,這裡可以使用泛型來作為輸入引數,控制引數的輸入型別。

public abstract class AbstractCarFactory {
    public abstract  <T extends Car> T createCar(Class<T> clazz);
}

這裡使用泛型首先定義了泛型 T 是 Car 的子類,限制了 T 的型別,其次是輸入引數必須是 Class 型別。

1.4 汽車建立工廠

接下來,我們定義一個實際的汽車建立工廠:

public class CarFactory extends AbstractCarFactory {
    @Override
    public <T extends Car> T createCar(Class<T> clazz) {
        Car car = null;
        try {
            car = (T)Class.forName(clazz.getName()).newInstance();
        } catch (Exception e) {
            System.out.println("汽車生產出錯啦,請回爐重造!");
        }
        return (T) car;
    }
}

1.5 開始生產汽車

public class Test {
    public static void main(String[] args) {
        AbstractCarFactory carFactory = new CarFactory();
        System.out.println("-- 第一輛車生產特斯拉 --");
        Car tesla = carFactory.createCar(Tesla.class);
        tesla.name();
        tesla.drive();

        System.out.println("-- 第二輛車生產賓士 --");
        Car benz = carFactory.createCar(Benz.class);
        benz.name();
        benz.drive();

        System.out.println("-- 第三輛車生產奧迪 --");
        Car audi = carFactory.createCar(Audi.class);
        audi.name();
        audi.drive();
    }
}

生產的結果如下:

-- 第一輛車生產特斯拉 --
我是特斯拉!!!
我是特斯拉,速度賊快!!!
-- 第二輛車生產賓士 --
我是賓士!!!
我是賓士,內飾豪華!!!
-- 第三輛車生產奧迪 --
我是奧迪!!!
我是奧迪,科技感十足!!!

2. 工廠模式

首先是工廠模式的定義:

Define an interface for creating an object,but let subclasses decide whichclass to instantiate.Factory Method lets a class defer instantiation tosubclasses.(定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。)

下面是一個通用類圖:

  • Product: 用於定義產品特性,實現對事物最抽象的定義,就像上面定義的 Car 。
  • ConcreteProduct: 具體對產品定義的實現,就上上面定義的特斯拉和奧迪。
  • Creator: 抽象工廠,用於最抽象對 Product 的構造的定義。
  • ConcreteCreator: Creator 的具體實現,具體實現如何建立產品類。

2.1 抽象產品類

public abstract class Product {
    public void method1() {

    }
    public abstract void method2();
}

2.2 具體產品類

public class ConcreteProduct1 extends Product {
    @Override
    public void method2() {

    }
}

public class ConcreteProduct2 extends Product {
    @Override
    public void method2() {

    }
}

具體的產品類可以有多個,都繼承於抽象的產品類。

2.3 抽象工廠類

public abstract class Creator {
    public abstract <T extends Product> T createProduct(Class<T> clazz);
}

2.4 具體工廠類

public class ConcreteCreator extends Creator {
    @Override
    public <T extends Product> T createProduct(Class<T> clazz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clazz.getName()).newInstance();
        } catch (Exception e) {
            // 異常處理
        }
        return (T) product;
    }
}

具體如何產生一個產品的物件的實現,是由具體的工廠類進行實現的,具體的工廠類可以有多個,用於實現多條產品線的生產。

2.5 優點

  • 良好的封裝性,程式碼結構清晰。
  • 良好的擴充套件性。如果我們需要增加產品類,只需要修改具體的工廠類或者擴充套件一個新的具體工廠類即可。
  • 遮蔽產品類。工廠模式是點型的解耦框架,高層次的模組只需要知道產品的抽象類,其他的實現類都不需要關心。

3. 工廠模式擴充套件——多個工廠類

前面說工廠模式可以有多個具體工廠,如果專案複雜度足夠高,將所有的產品都放在一個工廠類中做初始化有點不夠清晰,那麼我們可以實現多個工廠類,由每一個工廠類對應不同的業務規則做對應的產品類的初始化操作。

我如果把上面的那個超級汽車工廠改成多工廠類,先畫一個類圖:

這個程式碼我就不寫了,和上面的差不多,就是從原來的一個工廠生產三種車變成了三個專屬工廠生產三種車。

相關文章