設計模式-工廠模式

1、概述

回顧:MySQL存儲引擎如何創建我的博客html

我的博客:後臺建站,適合java程序員java

什麼是工廠模式?

工廠模式(Factory Pattern)是最多見的一種設計模式之一。它主要是提供一種建立對象的最佳方法!程序員

爲何要學習工廠模式?

與經過new來建立對象不一樣,使用工廠模式建立對象不會對客戶端暴露建立邏輯,而且是經過統一個共同的接口指向新建立的對象。同事工廠模式能將建立對象的代碼集中在一個對象或者方法中,能夠避免代碼中的重複,而且更方便維護。面向接口編程,這樣的代碼更具備彈性,能夠應對將來的擴展。編程

2、認識工廠模式

案例:假設你有一個Pizza店,天天要作出不一樣口味的Pizza。設計模式

假設咱們有兩種口味Pizzacookie

/*
 * 抽象的Pizza類,Pizza製做通常包括準備,烘烤,切塊,包裝。
 */
public abstract class Pizza{
     // Pizza名稱
     protected String name;
     // 麪糰類型
     protected String dough;
     // 醬料
     protected String sauce;
     // 芝士
     protected String cheese;
     // 蛤蜊
     protected String clam;
     // 佐料
     protected List toppings = new ArrayList();
    
    // 準備
    public  void prepare() {
        System.out.print("準備食材,添加調料:");
        for (int i = 0; i < toppings.size(); i++) {
            System.out.print(toppings.get(i)+" ");
        }
    };
    // 烘烤
    public  void bake() {
        System.out.println("烘烤20分鐘...");
    };
    // 切塊
    public void cut() {
        System.out.println("切成x塊...");
    };
    // 包裝
    public void box() {
        System.out.println("包裝...");
    }
    // setter 和 getter方法省略
}

芝加哥風味的芝士Pizza框架

public class ChicagoStyleCheesePizza extends Pizza{

    public ChicagoStyleCheesePizza() {

        name = "Chicago Style Deep Dish Cheese Pizza";

        dough = "Extra Thick Crust Dough";

        sauce = "Plum Tomato Sauce";

        toppings.add("Shredded Mozzarella Cheese");

    }   
    public void cut() {
        System.out.println("Cut the pizza into square slices");
    }
}

紐約風味的蔬菜Pizza學習

public class NyStyleVeggiePizza extends Pizza{
    public NyStyleVeggiePizza() {
        name = "NY style Sauce and Veggie Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Veggie");
    }
}

紐約風味的芝士Pizzathis

public class NyStyleCheesePizza extends Pizza{
    public NyStyleCheesePizza() {
        name = "NY style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Cheese");
    }
}

經過new建立對象設計

// 建立一個紐約風味的芝士Pizza
NyStyleCheesePizza nyPizza = new NyStyleCheesePizza();

當使用new獲得一個對象時,確實獲得了一個具體類,是針對具體類實現,而不是接口。代碼綁定具體類會致使代碼脆弱,更缺少彈性。

簡單工廠

public class SimplePizzaFactory {
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        if (type.equals("NyStyleCheesePizza")) {
            return new NyStyleChieesePizza();
        } else if(type.endsWith("ChicagoStyleCheesePizza")) {
            return new ChicagoStyleCheesePizza();
        }else {
            return null;
        }
    }
}
// 建立簡單工廠對象
SimplePizzaFactory pizzaFactory = new SimplePizzaFactory();
// 建立Pizza對象
NyStyleChieesePizza myPizza = pizzaFactory.createPizza("NYStyleChieesePizza");

簡單工廠將對象的建立過程進行了封裝,用戶不須要知道具體的建立過程,只須要調用工廠類獲取對象便可。

這種簡單工廠的寫法是經過if else來判斷對象建立過程的。簡單工廠只是把new對象的問題轉移到另外一個類中在實際使用過程當中,違背了 開放-關閉原則,固然有些狀況下能夠經過反射調用來彌補這種不足。

工廠方法模式

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

// 抽象的Pizza工廠
public abstract class PizzaFactory {
    public Pizza getPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        
        return pizza;
    }
    protected abstract Pizza createPizza(String pizza);
}
// 紐約Pizza工廠(芝加哥pizza工廠跟這個相似)
public class NYPizzaFactory extends PizzaFactory {

    protected Pizza createPizza(String type) {
        if (type.equals("NyStyleChieesePizza")) {
            return new NyStyleCheesePizza();
        } else if (type.equals("NyStyleVeggiePizza")) {
            return new NyStyleVeggiePizza();
        }else {
            return null;
        }
    }
}

經過工廠方法建立對象

PizzaFactory pizzaFactory = new NYPizzaFactory();
// 建立一個蔬菜披薩
Pizza pizza = pizzaFactory.createPizza("NyStyleVeggiePizza");

當使用工廠方法建立對象時,是在編寫具體工廠類時決定建立的對象時哪個,選擇使用哪一個工廠類,天然就決定了十幾建立的是哪一個對象。儘管只有一個具體工廠,工廠方法仍是很是有用的!由於它將對象從「實現」從「使用」中解耦若是增長對象或者改變對象,工廠是不會受到影響的

抽象工廠模式

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

抽象原料工廠

// 爲了簡化, 這裏的原料用字符串表示,其實每一個原料應該用一個類表示
public interface PizzaIngredientFactory {
    public String createDough();
    public String createSauce();
    public String createChieese();
    public String[] createVeggies();
    public String createPepperoni();
}

芝士pizza原料工廠

public class CheesePizzaIngredientFactory implements PizzaIngredientFactory {

    public String createDough() {
        return "薄地殼比薩生麪糰";
    }

    public String createSauce() {
        return "紐約專用蘸料";
    }

    public String createChieese() {
        return "Reggiano乾酪";
    }

    public String[] createVeggies() {
         
        return new String[]{"洋蔥","生菜","香菇"};
    }
    public String createPepperoni() {
        return "意大利辣香腸";
    }
}

建立pizza工廠

public class ChinaPizzaFactory extends PizzaFactory {
    
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new ChinaPizzaIngredientFactory();
        if(type.equals("cheese")) {
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("中國芝士pizza");
        }else if (type.equals("clam")) {
            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("中國蛤蜊pizza");
        }
        return pizza;
    }
}
// 具體的Pizza類
public class ClamPizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;
    
    public ClamPizza(PizzaIngredientFactory pizzaIngredientFactory) {
        this.ingredientFactory = pizzaIngredientFactory;
    }

    public void prepare() {
        System.out.println("Preparinging" + name);
        // 根據pizza自己的特色,從工廠中獲取本身須要的原料
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        clam = ingredientFactory.creatClam();
    }
}

建立一箇中國蛤蜊pizza

// 建立一個Pizza工廠
PizzaFactory pizzaFactory = new ChinaPizzaFactory();
Pizza clamPizza = pizzaFactory.createPizza("clam");

抽象工廠模式將'對象' 與 ‘’組成對象或者對象依賴的類‘’解耦。

3、對比與分析

經過new來建立對象是面向具體類編程,擴展性差!

簡單工廠把所有的事情都在一個地方處理完了,可是當有新增或者修改的對象類時,很難進行擴展,違反了開閉原則。簡單工廠並不能算是工廠模式,而是一種編程習慣,或者是一種方法的封裝,並不具有彈性。

工廠方法是建立一個框架,讓子類決定如何實現。雖然可能致使類會變多,代碼稍微複雜,可是這樣作最大的好處是更具備彈性。

工廠模式的好處:將建立對象的代碼集中在一個對象或者方法中,能夠避免代碼中重複的代碼,而且方便之後的維護。依賴接口,而不是具體的類。

如何選擇?

當須要將對象家族和具體的對象集合結合起來時,可使用抽象工廠。

當須要將客戶代碼從須要實例化的具體類中解耦,或者目前還不中知道未來實例化哪些具體類時,可使用工廠方法。

相關文章
相關標籤/搜索