設計模式|05 抽象工廠模式

  • 2019 年 10 月 7 日
  • 筆記

部落客的部落格地址: https://www.jeffcc.top/ 部落客學習設計模式用的書是Head First的《設計模式》,強烈推薦配套使用!

什麼是抽象工廠模式

權威定義:抽象工廠模式提供一個介面,用於創建相關或依賴對象的家族,而不需要明確指定具體的類。 部落客的理解:抽象工廠的任務就是定義一個負責創建一組產品的介面,介面的內部的每個方法都負責創建一個具體的產品,所以可以理解為抽象工廠就是多個工廠方法的高聚合的體現。

抽象工廠模式和工廠方法模式的比較

  1. 工廠方法使用繼承,把對象的創建委託給子類,子類實現工廠方法來創建對象;
  2. 抽象工廠使用的是對象組合,對象的創建被實現在工廠介面所暴露出來的方法中;
  3. 工廠方法允許類將實例化延遲到子類進行;
  4. 抽象工廠創建相關的對象家族,而不需要依賴他們的具體類;

設計原則

  1. 依賴倒置原則,要依賴抽象,不要依賴具體類,具體做法是需要高層組件(工廠)和底層組件(實現類)之間不要有太多的依賴關係,而是可以通過一個共同的抽象類(工廠產生的對象)來實現依賴倒置。
  2. 多用組合,少用繼承。
  3. 針對介面編程,而不是針對實現編程。
  4. 為交互對象之間的松耦合設計而努力。
  5. 類應該對外開放拓展,對修改關閉。

設計實例

設計背景

利用上一篇部落格講到的pizza店為拓展,為了規範化加盟店,新加一個原料工廠,各個地區有自己不同的風格的原料,但是都必須遵守原料工廠所提供的的原料標準(介面規範化)

項目類圖

項目結構

披薩工廠

package factory;    import pizza.Pizza;    /**   * 披薩工廠   */  public abstract class PizzaStore {        public Pizza orderPizza(String type){          Pizza pizza;  //        進行創建pizza          pizza = createPizza(type);  //        下面進行的是共同的東西,所以封裝起來到工廠中          pizza.prepare();          pizza.bake();          pizza.cut();          pizza.box();            return pizza;        }        /**       * 抽取出一個抽象的製作pizza的方法來交給子類具體實現       * 工廠模式的關鍵所在       * @param type  什麼風味的pizza       * @return       */      public abstract Pizza createPizza(String type);    }  

ChicagoPizzaStore加盟店

package store;    import factory.PizzaStore;  import ingredientfactory.PizzaIngredientFactory;  import ingredientfactory.impl.ChicagoPizzaIngredientFactory;  import pizza.Pizza;  import pizza.impl.ChicagoStyleCheesePizza;    /**   * ChicagoPizzaStore加盟店   */  public class ChicagoPizzaStore extends PizzaStore {    //    配置芝加哥原料工廠      PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory();      /**       * 模擬測試生產pizza  太多類型了就寫一個 理論可以無限拓展       * @param type 什麼風味的pizza       * @return       */      @Override      public Pizza createPizza(String type) {          if ("cheese".equals(type)) {              return new ChicagoStyleCheesePizza(ingredientFactory);          } else {              return null;          }      }  }  

紐約pizza加盟店

package store;    import factory.PizzaStore;  import ingredientfactory.PizzaIngredientFactory;  import ingredientfactory.impl.NYPizzaIngredientFactory;  import pizza.Pizza;  import pizza.impl.NYStyleCheesePizza;    /**   * 紐約pizza加盟店   */  public class NYPizzaStore extends PizzaStore {    //    配置原料加工工廠      PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();      /**       * 模擬測試生產pizza  太多類型了就寫一個 理論可以無限拓展       * @param type 什麼風味的pizza       * @return       */      @Override      public Pizza createPizza(String type) {          if ("cheese".equals(type)) {              return new NYStyleCheesePizza(ingredientFactory);          } else {              return null;          }      }  }  

Pizza抽象類(關鍵)

package pizza;    import ingredient.*;    /**   * pizza的抽象類   * 也就是之前說的依賴倒置所依賴的類!!!   * 需要有pizza的操作的方法   */  public abstract class Pizza {        public String name;      public Cheese cheese;      public Clams clams;      public Dough dough;      public Pepperoni pepperoni;      public Sauce sauce;      public Veggies[] veggies;        /**       * 提供默認的基本做法 進行烘烤、切片、裝盒 如果需要可以進行重寫       */  //    對準備方法進行抽象化  接入工廠的原料準備!      public abstract void prepare();        /**       * 烘烤       */      public void bake() {          System.out.println("Bake for 25 minutes at 350");      }        /**       * 切片       */      public void cut() {          System.out.println("Cutting the pizza into diagonal slices!");      }        /**       * 裝盒       */      public void box() {          System.out.println("Place pizza in official PizzaStore box");      }        public String getName() {          return name;      }  }  

ChicagoStyleCheesePizza 芝加哥風味

package pizza.impl;    import ingredient.Veggies;  import ingredientfactory.PizzaIngredientFactory;  import pizza.Pizza;    /**   * 實現不同的風味的pizza ChicagoStyleCheesePizza   */  public class ChicagoStyleCheesePizza extends Pizza {        PizzaIngredientFactory pizzaIngredientFactory;    //    初始化pizza風味需要的原料工廠      public ChicagoStyleCheesePizza(PizzaIngredientFactory pizzaIngredientFactory) {          this.pizzaIngredientFactory = pizzaIngredientFactory;          super.name = "ChicagoStyleCheesePizza";      }        /**       * 設置風味       * 變化之處!       * 原料從工廠中獲得!       */      @Override      public void prepare() {          System.out.println("Preparing:"+super.getName());          System.out.println("Using Ingredient:");  //        所有的原料都是從工廠中獲得的 而且是成套獲得 這體現了抽象工廠方法的優勢 將所有的工廠組合到一個介面中          cheese = pizzaIngredientFactory.createCheese();          clams = pizzaIngredientFactory.createClams();          dough = pizzaIngredientFactory.createDough();          pepperoni = pizzaIngredientFactory.createPepperoni();          sauce = pizzaIngredientFactory.createSauce();          veggies = pizzaIngredientFactory.createVeggies();  //        獲取到之後進行輸出          System.out.println(cheese.getCheese());          System.out.println(clams.getClams());          System.out.println(dough.getDough());          System.out.println(pepperoni.getPepperoni());          System.out.println(sauce.getSauce());          for (Veggies veggy : veggies) {              System.out.print(veggy.getVeggies()+" ");          }          System.out.println();      }        /**       * 模擬需要有不同的切片方法       */      @Override      public void cut() {          System.out.println("Cutting the pizza into square slices");      }  }  

紐約風味pizza

package pizza.impl;    import ingredient.Veggies;  import ingredientfactory.PizzaIngredientFactory;  import pizza.Pizza;    /**   * 實現不同的風味的pizza 紐約風味   */  public class NYStyleCheesePizza extends Pizza {        /**       * 設置風味       */      PizzaIngredientFactory pizzaIngredientFactory;        //    初始化pizza風味需要的原料工廠      public NYStyleCheesePizza(PizzaIngredientFactory pizzaIngredientFactory) {          this.pizzaIngredientFactory = pizzaIngredientFactory;          super.name = "NYStyleCheesePizza";      }        /**       * 設置風味       * 變化之處!       * 原料從工廠中獲得!       */      @Override      public void prepare() {          System.out.println("Preparing:"+super.getName());          System.out.println("Using Ingredient:");  //        所有的原料都是從工廠中獲得的 而且是成套獲得 這體現了抽象工廠方法的優勢 將所有的工廠組合到一個介面中          cheese = pizzaIngredientFactory.createCheese();          clams = pizzaIngredientFactory.createClams();          dough = pizzaIngredientFactory.createDough();          pepperoni = pizzaIngredientFactory.createPepperoni();          sauce = pizzaIngredientFactory.createSauce();          veggies = pizzaIngredientFactory.createVeggies();          //        獲取到之後進行輸出          System.out.println(cheese.getCheese());          System.out.println(clams.getClams());          System.out.println(dough.getDough());          System.out.println(pepperoni.getPepperoni());          System.out.println(sauce.getSauce());          for (Veggies veggy : veggies) {              System.out.print(veggy.getVeggies()+" ");          }          System.out.println();      }  }  

原料工廠(關鍵)

package ingredientfactory;    import ingredient.*;    /**   * 原料工廠   * 提供一套的方法進行原料的創建   * 這裡體現出了抽象工廠模式的特點   * 使用組合的方法將多個工廠的方法組合在一起   */  public interface PizzaIngredientFactory {      Dough createDough();      Sauce createSauce();      Cheese createCheese();      Veggies[] createVeggies();      Pepperoni createPepperoni();      Clams createClams();  }      芝加哥的原料提供廠package ingredientfactory.impl;    import ingredient.*;  import ingredient.cheeseImpl.ReggianoCheese;  import ingredient.clamsImpl.FrozenClams;  import ingredient.doughImpl.ThickCrustDough;  import ingredient.pepperoniImpl.pepperoni02;  import ingredient.sauceImpl.PlumTomatpSauce;  import ingredient.veggiesImpl.Veggies02;  import ingredient.veggiesImpl.Veggies03;  import ingredientfactory.PizzaIngredientFactory;    /**   * 實現了芝加哥的原料提供廠   */  public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {      @Override      public Dough createDough() {          return new ThickCrustDough();      }        @Override      public Sauce createSauce() {          return new PlumTomatpSauce();      }        @Override      public Cheese createCheese() {          return new ReggianoCheese();      }        @Override      public Veggies[] createVeggies() {          Veggies[] veggies = {new Veggies02(),new Veggies03()};          return veggies;      }        @Override      public Pepperoni createPepperoni() {          return new pepperoni02();      }        @Override      public Clams createClams() {          return new FrozenClams();      }  }  

紐約的原料提供廠

package ingredientfactory.impl;    import ingredient.*;  import ingredient.cheeseImpl.MozzarellaCheese;  import ingredient.clamsImpl.FreshClams;  import ingredient.doughImpl.ThinCrustDough;  import ingredient.pepperoniImpl.pepperoni01;  import ingredient.sauceImpl.MarinaraSauce;  import ingredient.veggiesImpl.Veggies01;  import ingredient.veggiesImpl.Veggies03;  import ingredientfactory.PizzaIngredientFactory;    /**   * 實現了紐約的原料提供廠   */  public class NYPizzaIngredientFactory implements PizzaIngredientFactory {      @Override      public Dough createDough() {          return new ThinCrustDough();      }        @Override      public Sauce createSauce() {          return new MarinaraSauce();      }        @Override      public Cheese createCheese() {          return new MozzarellaCheese();      }        @Override      public Veggies[] createVeggies() {          Veggies[] veggies = {new Veggies01(),new Veggies03()};          return veggies;      }        @Override      public Pepperoni createPepperoni() {          return new pepperoni01();      }        @Override      public Clams createClams() {          return new FreshClams();      }  }

原料介面規範

package ingredient;    public interface Dough {      String getDough();  }    package ingredient;    public interface Cheese {      String getCheese();  }    package ingredient;    public interface Clams {      String getClams();  }    package ingredient;    public interface Pepperoni {      String getPepperoni();  }    package ingredient;    public interface Sauce {      String getSauce();  }    package ingredient;    public interface Veggies {      String getVeggies();  }

不同地區的原料實現類

package ingredient.cheeseImpl;    import ingredient.Cheese;    /**   * cheese原料1 MozzarellaCheese   */  public class MozzarellaCheese implements Cheese {      private String cheese = "MozzarellaCheese";        public String getCheese() {          return cheese;      }    }    package ingredient.cheeseImpl;    import ingredient.Cheese;    /**   * cheese原料1 ReggianoCheese   */  public class ReggianoCheese implements Cheese {      private String cheese = "ReggianoCheese";        public String getCheese() {          return cheese;      }    }    package ingredient.doughImpl;    import ingredient.Dough;    /**   * 原料2 ThickCrustDough   */  public class ThickCrustDough implements Dough {      private String dough = "ThickCrustDough";        public String getDough() {          return dough;      }  }    package ingredient.doughImpl;    import ingredient.Dough;    /**   * 原料2 ThinCrustDough   */  public class ThinCrustDough implements Dough {      private String dough = "ThinCrustDough";        public String getDough() {          return dough;      }  }    package ingredient.clamsImpl;    import ingredient.Clams;    /**   * 原料3 FreshClams   */  public class FreshClams implements Clams {      private String clams = "FreshClams";        public String getClams() {          return clams;      }  }    package ingredient.clamsImpl;    import ingredient.Clams;    /**   * 原料3 FrozenClams   */  public class FrozenClams implements Clams {      private String clams = "FrozenClams";        public String getClams() {          return clams;      }  }    package ingredient.sauceImpl;    import ingredient.Sauce;    /**   * 原料4 MarinaraSauce   */  public class MarinaraSauce implements Sauce {      private String sauce = "MarinaraSauce";        public String getSauce() {          return sauce;      }  }    package ingredient.sauceImpl;    import ingredient.Sauce;    /**   * 原料4 PlumTomatpSauce   */  public class PlumTomatpSauce implements Sauce {      private String sauce = "PlumTomatpSauce";        public String getSauce() {          return sauce;      }  }    package ingredient.veggiesImpl;    import ingredient.Veggies;    /**   * 原料5 Veggies01   */  public class Veggies01 implements Veggies {      private String veggies = "Veggies01";        public String getVeggies() {          return veggies;      }  }    package ingredient.veggiesImpl;    import ingredient.Veggies;    /**   * 原料5 Veggies02   */  public class Veggies02 implements Veggies {      private String veggies = "Veggies02";        public String getVeggies() {          return veggies;      }  }    package ingredient.veggiesImpl;    import ingredient.Veggies;    /**   * 原料5 Veggies03   */  public class Veggies03 implements Veggies {      private String veggies = "Veggies03";        public String getVeggies() {          return veggies;      }  }    package ingredient.pepperoniImpl;    import ingredient.Pepperoni;    /**   * 原料6 pepperoni01   */  public class pepperoni01 implements Pepperoni {      private String pepperoni = "pepperoni01";        public String getPepperoni() {          return pepperoni;      }  }    package ingredient.pepperoniImpl;    import ingredient.Pepperoni;    /**   * 原料6 pepperoni02   */  public class pepperoni02 implements Pepperoni {      private String pepperoni = "pepperoni02";        public String getPepperoni() {          return pepperoni;      }  }  

輸出結果

PreparingNYStyleCheesePizza  Using Ingredient:  MozzarellaCheese  FreshClams  ThinCrustDough  pepperoni01  MarinaraSauce  Veggies01 Veggies03  Bake for 25 minutes at 350  Cutting the pizza into diagonal slices!  Place pizza in official PizzaStore box  jay order a NYStyleCheesePizza    PreparingChicagoStyleCheesePizza  Using Ingredient:  ReggianoCheese  FrozenClams  ThickCrustDough  pepperoni02  PlumTomatpSauce  Veggies02 Veggies03  Bake for 25 minutes at 350  Cutting the pizza into square slices  Place pizza in official PizzaStore box  jeff order a NYStyleCheesePizza

回歸定義

我們之前定義說的抽象工廠模式提供一個介面,用於創建相關或依賴對象的家族,而不需要明確指定具體的類。

在這個具體的實例中都有著對應的關係。 PizzaIngredientFactory提供了一個介面,裡面有著一個原料家族的創建的關係,並且這個PizzaIngredientFactory類並沒有指定任何的具體的類; 而我們也很容易看出,如果把原料分離開來單獨寫,那麼就是一個一個的小工廠,所以說抽象工廠模式其實通俗來說就是一個大工廠裡面有好多個小工廠!