天天看點

簡單工廠模式-Simple Factory

引入案例——咖啡店點餐系統:

要求:

設計一個咖啡類(Coffee),并定義其兩個子類(美式咖啡【AmericanCoffee】和拿鐵咖啡【LatteCoffee】);再設計一個咖啡店類(CoffeeStore),咖啡店具有點咖啡的功能。

先看看沒有使用簡單工廠模式的實作

UML類圖如下:

簡單工廠模式-Simple Factory

Code如下:

(1)Main方法

package 簡單工場;

public class coffeeTest {
    public static void main(String[] args) {
        //1.建立咖啡店類
        CoffeeStore store = new CoffeeStore();
        //2.點咖啡
        Coffee coffee = store.orderCoffee("latte");

        System.out.println(coffee.getName());
    }
}
           

(2)Coffee類

package 簡單工場;

public abstract class Coffee {

    public abstract String getName();
    //加糖
    public void addSugar(){
        System.out.println("加糖");
    }
    //加奶
    public void addMilk(){
        System.out.println("加奶");
    }

}
           

(3)AmericanCoffee類

package 簡單工場;

public class AmericanCoffee extends Coffee{
    public String getName(){
        return "美式咖啡";
    }
}
           

(4)LatteCoffee類

package 簡單工場;

public class LatteCoffee extends Coffee{
    public String getName(){
        return "拿鐵咖啡";
    }
}
           

(5)CoffeeStore類

package 簡單工場;

public class CoffeeStore {
    public Coffee orderCoffee(String type){
        //聲明Coffee類型的變量,根據不同類型建立不同的Coffee的子類對象
        //初始化
        Coffee coffee = null;
        if ("amerian".equals(type)){
            coffee = new AmericanCoffee();
        }else if ("latte".equals(type)){
            coffee = new LatteCoffee();
        }else {
            throw new RuntimeException("對不起,你所點咖啡沒有");
        }
        //加配料
        coffee.addMilk();
        coffee.addSugar();

        return coffee;
    }
}
           

運作如下:

簡單工廠模式-Simple Factory

存在問題:

如果要更換一種coffee需要需改main中orderCoffee方法中的參數,這裡就兩個類,but有很多個類呢?顯然這就違背了設計模式七大原則中的開閉原則!

在java中,萬物皆對象,這些對象都需要建立,如果建立的時候直接new該對象,就會對該對象耦合嚴重,假如我們要更換對象,所有new對象的地方都需要修改一遍,這顯然違背了軟體設計的開閉原則。

如果我們使用工廠來生産對象,我們就隻和工廠打交道就可以了,徹底和對象解耦,如果要更換對象,直接在工廠裡更換該對象即可,達到了與對象解耦的目的;是以說,工廠模式最大的優點就是:解耦。

簡單工廠模式

簡單工廠不是一種設計模式,反而比較像是一種程式設計習慣。

簡單工廠包含如下角色:

  • 抽象産品 :定義了産品的規範,描述了産品的主要特性和功能。
  • 具體産品 :實作或者繼承抽象産品的子類
  • 具體工廠 :提供了建立産品的方法,調用者通過該方法來擷取産品。

UML類圖:

簡單工廠模式-Simple Factory

代碼如下:

其中coffeeTest類,Coffee類,AmericanCoffee類,LatteCoffee類不用需改。

(1)添加一個類,SimpleCoffeeFactory

package 簡單工場;

public class SimpleCoffeeFactory {
    public Coffee createCoffee(String type){
        Coffee coffee = null;
        if ("amerian".equals(type)){
            coffee = new AmericanCoffee();
        }else if ("latte".equals(type)){
            coffee = new LatteCoffee();
        }else {
            throw new RuntimeException("對不起,你所點咖啡沒有");
        }
        return coffee;
    }
}
           

(2)将上面寫的CoffeeStore類修改一下

package 簡單工場;

public class CoffeeStore {
    public Coffee orderCoffee(String type){

        SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
        Coffee coffee = factory.createCoffee(type);

        coffee.addSugar();
        coffee.addMilk();
        return coffee;
    }
}
           

顯然,這樣子使用了SimpleCoffeeFactory類,在建立一個類的時候,就不會再依賴具體的産品對象了!

總結:

工廠(factory)處理建立對象的細節,一旦有了SimpleCoffeeFactory,CoffeeStore類中的orderCoffee()就變成此對象的客戶,後期如果需要Coffee對象直接從工廠中擷取即可。這樣也就解除了和Coffee實作類的耦合,同時又産生了新的耦合,CoffeeStore對象和SimpleCoffeeFactory工廠對象的耦合,工廠對象和商品對象的耦合。

後期如果再加新品種的咖啡,我們勢必要需求修改SimpleCoffeeFactory的代碼,違反了開閉原則。工廠類的用戶端可能有很多,比如建立美團外賣等,這樣隻需要修改工廠類的代碼,省去其他的修改操作。

優點:

封裝了建立對象的過程,可以通過參數直接擷取對象。把對象的建立和業務邏輯層分開,這樣以後就避免了修改客戶代碼,如果要實作新産品直接修改工廠類,而不需要在原代碼中修改,這樣就降低了客戶代碼修改的可能性,更加容易擴充。

缺點:

增加新産品時還是需要修改工廠類的代碼,違背了“開閉原則”。(雖然也是違背了開閉原則,但是比不使用直接建立對象要好得多!)

擴充:

在開發中也有一部分人将工廠類中的建立對象的功能定義為靜态的,這個就是靜态工廠模式,它也不是23種設計模式中的。代碼如下:

隻要需改一下SimpleCoffeeFactory即可(加一個static即可)

public class SimpleCoffeeFactory {

    public static Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffe;
    }
}
           

在CoffeeStore中隻要修改一下調用靜态方法即可!

Coffee coffee = SimpleCoffeeFactory.createCoffee(type);
package 簡單工場;

public class CoffeeStore {
    public Coffee orderCoffee(String type){

        //修改了這裡,不用建立SimpleCoffeeFactory類了
        Coffee coffee = SimpleCoffeeFactory.createCoffee(type);

        coffee.addSugar();
        coffee.addMilk();
        return coffee;
    }
}