Java設計模式之工廠模式

工廠模式有三種:簡單工廠模式、工廠方法模式、抽象工廠模式。

這裏以製造coffee的例子開始工廠模式設計之旅。我們知道coffee只是一種泛舉,在點購咖啡時需要指定具體的咖啡種類:美式咖啡、卡布奇諾、拿鐵等等。

接口獲取coffee

public abstract class Coffee {
    public abstract String getName();
}

不同咖啡的創建

// 美式咖啡
public class Americano extends Coffee {

    @Override
    public String getName() {
        return "美式咖啡";
    }

}


//卡布奇諾
public class Cappuccino extends Coffee {

    @Override
    public String getName() {
        return "卡布奇諾";
    }

}


// 拿鐵
public class Latte extends Coffee {

    @Override
    public String getName() {
        return "拿鐵";
    }

}

一、簡單工廠模式


public class SimpleFactory {
    
    /**
     * 通過類型獲取Coffee實例對象
     */
    public static Coffee createInstance(String type){
        if("americano".equals(type)){
            return new Americano();
        }else if("cappuccino".equals(type)){
            return new Cappuccino();
        }else if("latte".equals(type)){
            return new Latte();
        }else{
            throw new RuntimeException("type["+type+"]類型不可識別,沒有匹配到可實例化的對象!");
        }
    }
    
    public static void main(String[] args) {
        Coffee latte = SimpleFactory.createInstance("latte");
        System.out.println("創建的咖啡實例爲:" + latte.getName());
    }

}

特點
1、它是一個具體的類,非接口抽象類。有一個重要的create()方法,利用 if 或者 switch 創建產品並返回。create()方法通常是靜態的,所以也稱之爲靜態工廠。
2、擴展性差(我想增加一種麪條,除了新增一個麪條產品類,還需要修改工廠類方法)。

二、工廠方法模式

定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個,工廠方法讓類把實例化推遲到了子類。

場景延伸:不同地區咖啡工廠受制於環境、原料等因素的影響,製造出的咖啡種類有限。中國咖啡工廠僅能製造卡布奇諾、拿鐵,而美國咖啡工廠僅能製造美式咖啡、拿鐵。

定義一個抽象的咖啡工廠

public abstract class CoffeeFactory {
    
    /**
     * 生產可製造的咖啡
     * @return
     */
    public abstract Coffee[] createCoffee();

}

子類實現工廠方法

子類實現工廠方法
/**
 * 中國咖啡工廠,製造卡布奇諾和拿鐵
 */
public class ChinaCoffeeFactory extends CoffeeFactory {

    @Override
    public Coffee[] createCoffee() {
        return new Coffee[]{new Cappuccino(), new Latte()};
    }

}


/**
 * 美國咖啡工廠,製造美式咖啡和拿鐵
 */
public class AmericaCoffeeFactory extends CoffeeFactory {

    @Override
    public Coffee[] createCoffee() {
        return new Coffee[]{new Americano(), new Latte()};
    }

}

測試類

public class FactoryMethodTest {

    private static void print(Coffee[] c){
        for (Coffee coffee : c) {
            System.out.println(coffee.getName());
        }
    }
    
    public static void main(String[] args) {
        CoffeeFactory chinaCoffeeFactory = new ChinaCoffeeFactory();
        Coffee[] chinaCoffees = chinaCoffeeFactory.createCoffee();
        System.out.println("中國咖啡工廠可以生產的咖啡有:");
        print(chinaCoffees);
        CoffeeFactory americaCoffeeFactory = new AmericaCoffeeFactory();
        Coffee[] americaCoffees = americaCoffeeFactory.createCoffee();
        System.out.println("美國咖啡工廠可以生產的咖啡有:");
        print(americaCoffees);
    }
}

輸出:
中國咖啡工廠可以生產的咖啡有:
卡布奇諾
拿鐵
美國咖啡工廠可以生產的咖啡有:
美式咖啡
拿鐵

特點
1、相比簡單工廠方法,增加了一個抽象類(或者接口),由不同的產品工廠去實現該接口;
1、可以一定程度增加擴展性,若增加一個產品實現,只需要實現產品接口,修改工廠創建產品的方法,消費者可以無感知(若消費者不關心具體產品是什麼的情況);
2、可以一定程度增加代碼的封裝性、可讀性。清楚的代碼結構,對於消費者來說很少的代碼量就可以完成很多工作;

適用場景
1、消費者不關心它所要創建對象的類(產品類)的時候。
2、消費者知道它所要創建對象的類(產品類),但不關心如何創建的時候。

三、抽象工廠模式

提供一個接口,用於創建相關或依賴對象的家族,而不需要明確指定具體類。

在上述的場景上繼續延伸:咖啡工廠做大做強,引入了新的飲品種類:茶、 碳酸飲料。中國工廠只能製造咖啡和茶,美國工廠只能製造咖啡和碳酸飲料。如果用上述工廠方法方式,除去對應的產品實體類還需要新增2個抽象工廠(茶製造工廠、碳酸飲料製造工廠),4個具體工廠實現。隨着產品的增多,會導致類爆炸。所以這裏引出一個概念產品家族,在此例子中,不同的飲品就組成我們的飲品家族, 飲品家族開始承擔創建者的責任,負責製造不同的產品。

抽象的飲料產品家族製造工廠

public interface AbstractDrinksFactory {

    /**
     * 製造咖啡
     */
    Coffee createCoffee();
    
    /**
     * 製造茶
     */
    Tea createTea();
    
    /**
     * 製造碳酸飲料
     */
    Sodas createSodas();
}

中國飲品工廠,製造咖啡與茶

public class ChinaDrinksFactory implements AbstractDrinksFactory {

    @Override
    public Coffee createCoffee() {
        return new Latte();
    }

    @Override
    public Tea createTea() {
        return new MilkTea();
    }

    @Override
    public Sodas createSodas() {
        return null;
    }

}

美國飲品製造工廠,製造咖啡和碳酸飲料

public class AmericaDrinksFactory implements AbstractDrinksFactory {

    @Override
    public Coffee createCoffee() {
        return new Latte();
    }

    @Override
    public Tea createTea() {
        return null;
    }

    @Override
    public Sodas createSodas() {
        return new CocaCola();
    }

}

抽象工廠模式與工廠方法模式的區別:
抽象工廠模式是工廠方法模式的升級版本,他用來創建一組相關或者相互依賴的對象。他與工廠方法模式的區別就在於,工廠方法模式針對的是一個產品等級結構;而抽象工廠模式則是針對的多個產品等級結構。在編程中,通常一個產品結構,表現爲一個接口或者抽象類,也就是說,工廠方法模式提供的所有產品都是衍生自同一個接口或抽象類,而抽象工廠模式所提供的產品則是衍生自不同的接口或抽象類。

抽象工廠模式的優點:
抽象工廠模式除了具有工廠方法模式的優點外,最主要的優點就是可以在類的內部對產品族進行約束。所謂的產品族,一般或多或少的都存在一定的關聯,抽象工廠模式就可以在類內部對產品族的關聯關係進行定義和描述,而不必專門引入一個新的類來進行管理。

抽象工廠模式的缺點:
產品族的擴展將是一件十分費力的事情,假如產品族中需要增加一個新的產品,則幾乎所有的工廠類都需要進行修改。所以使用抽象工廠模式時,對產品等級結構的劃分是非常重要的。

適用場景:
當需要創建的對象是一系列相互關聯或相互依賴的產品族時,便可以使用抽象工廠模式。說的更明白一點,就是一個繼承體系中,如果存在着多個等級結構(即存在着多個抽象類),並且分屬各個等級結構中的實現類之間存在着一定的關聯或者約束,就可以使用抽象工廠模式。假如各個等級結構中的實現類之間不存在關聯或約束,則使用多個獨立的工廠來對產品進行創建,則更合適一點。

四、總結

1、簡單工廠:不能算是真正意義上的設計模式,但可以將客戶程序從具體類解耦,簡單方便易上手;

2、工廠方法:使用繼承,把對象的創建委託給子類,由子類來實現創建方法,可以看作是抽象工廠模式中只有單一產品的情況;

3、抽象工廠:使對象的創建被實現在工廠接口所暴露出來的方法中;

4、無論是簡單工廠模式,工廠方法模式,還是抽象工廠模式,他們都屬於工廠模式,在形式和特點上也是極爲相似的,他們的最終目的都是爲了解耦。在使用時,我們不必去在意這個模式到底工廠方法模式還是抽象工廠模式,因爲他們之間的演變常常是令人琢磨不透的。經常你會發現,明明使用的工廠方法模式,當新需求來臨,稍加修改,加入了一個新方法後,由於類中的產品構成了不同等級結構中的產品族,它就變成抽象工廠模式了;而對於抽象工廠模式,當減少一個方法使的提供的產品不再構成產品族之後,它就演變成了工廠方法模式。
 

參考:https://www.cnblogs.com/carryjack/p/7709861.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章