1. 程式人生 > 其它 >02.工廠設計模式

02.工廠設計模式

簡單工廠模式(靜態工廠模式)

  • 簡單工廠模式是屬於建立型模式,是工廠模式的的一種,簡單工廠模式是有一個工廠物件決定創建出那一種產品類的例項。簡單工廠模式是工廠模式家族的最簡單實用的模式。

  • 簡單工廠模式:定義一個建立物件的類,由這個類來建立例項化物件的行為(程式碼)

  • 在軟體開發當中,當我們會用到大量的建立某種、某類或者某批物件時,就會使用工廠模式。

  • 程式碼示例:

    /**
     * @author 通過程式看世界
     * @version 1.0
     * 將Pizza做成抽象類
     */
    public abstract class Pizza {
        protected String name; //披薩的名字
    
        //準備原材料,不同的披薩不一樣,因此.我們做成抽象方法
        public abstract void prepare();
    
        public void bake() {
            System.out.println(name + "backing");
        }
    
        public void cut() {
            System.out.println(name + "cutting");
        }
    
        //打包
        public void box() {
            System.out.println(name + "boxing");
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    }
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 乳酪披薩
     */
    public class CheesePizza extends Pizza {
        @Override
        public void prepare() {
            System.out.println("給製作乳酪披薩準備原材料");
        }
    }
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 希臘披薩
     */
    public class GreekPizza extends Pizza{
        @Override
        public void prepare() {
            System.out.println("給希臘披薩準備原材料");
        }
    }
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 簡單工廠類
     */
    public class SimpleFactor {
        //根據orderType返回對應的Pizza物件
        public Pizza createPizza(String type) {
            System.out.println("使用簡單工廠模式");
            Pizza pizza = null;
            if (type.equals("greek")){
                pizza = new CheesePizza();
                pizza.setName("希臘披薩");
            }else if (type.equals("cheese")){
                pizza = new CheesePizza();
                pizza.setName("乳酪披薩");
            }
            return pizza;
        }
    }
    
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 訂購披薩的類
     */
    public class OrderPizza {
        //定義一個一個簡單工廠物件
        SimpleFactor simpleFactor;
        Pizza pizza;
    
        public OrderPizza(SimpleFactor simpleFactor) {
            setSimpleFactor(simpleFactor);
        }
    
        public void setSimpleFactor(SimpleFactor simpleFactor) {
            String type = ""; //使用者輸入
            this.simpleFactor = simpleFactor; //設定簡單工廠物件
            do {
                type = getType();
                pizza = this.simpleFactor.createPizza(type);
    
                //輸出pizza
                if (pizza != null) {
                    pizza.prepare();
                    pizza.bake();
                    pizza.cut();
                    pizza.box();
                } else {
                    System.out.println("訂購pizza失敗!");
                    break;
                }
            } while (true);
    
        }
    
    
    
        //寫一個方法,可以獲取客戶希望訂購的Pizza種類
        private String getType() {
            try {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
                System.out.println("input pizza type:");
                String str = bufferedReader.readLine();
                return str;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
        }
    
    }
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 相當於一個客戶端
     */
    public class PizzaStore {
        public static void main(String[] args) {
            new OrderPizza(new SimpleFactor());
            System.out.println("退出程式");
        }
    }
    
  • 程式執行結果

    input pizza type:
    cheese
    使用簡單工廠模式
    給製作乳酪披薩準備原材料
    乳酪披薩backing
    乳酪披薩cutting
    乳酪披薩boxing
    input pizza type:
    greek
    使用簡單工廠模式
    給製作乳酪披薩準備原材料
    希臘披薩backing
    希臘披薩cutting
    希臘披薩boxing
    input pizza type:
    
  • 程式碼分析

    • 後期我們需要增加新的披薩型別,只需要在建立一個披薩類,在工廠類當中做出if判斷處理即可

工廠方式模式

  • 定義一個建立物件的抽象方法,由子類決定要例項化的類,工廠方法模式將物件的例項化推遲到子類。

  • 需求:客戶在點披薩的時候,可以點不同口味的披薩。比如:北京的乳酪pizza、北京的胡椒pizza、或者倫敦的乳酪pizza、倫敦的胡椒pizza

  • 程式碼例項:

    package com.db.factormethod.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 將Pizza做成抽象類
     */
    public abstract class Pizza {
        protected String name; //準備
    
        //準備原材料,不同的披薩不一樣,因此.我們做成抽象方法
        public abstract void prepare();
    
        public void bake() {
            System.out.println(name + "backing");
        }
    
        public void cut() {
            System.out.println(name + "cutting");
        }
    
        //打包
        public void box() {
            System.out.println(name + "boxing");
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    package com.db.factormethod.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 倫敦的胡椒披薩
     */
    public class LDPepperPizza extends Pizza{
        @Override
        public void prepare() {
            setName("倫敦的胡椒披薩");
            System.out.println("為倫敦的胡椒披薩準備原材料");
        }
    }
    
    package com.db.factormethod.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 倫敦的胡椒披薩
     */
    public class LDCheesePizza extends Pizza{
        @Override
        public void prepare() {
            setName("倫敦的胡椒披薩");
            System.out.println("為倫敦的胡椒披薩準備原材料");
        }
    }
    
    
    package com.db.factormethod.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     */
    public class BJPepperPizza extends Pizza{
        @Override
        public void prepare() {
            setName("北京的胡椒披薩");
            System.out.println("為北京的胡椒披薩準備原材料");
        }
    }
    
    
    package com.db.factormethod.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     */
    public class BJCheesePizza extends Pizza{
        @Override
        public void prepare() {
            setName("北京乳酪披薩");
            System.out.println("為北京的乳酪pizza準備原材料");
        }
    }
    
    
    package com.db.factormethod.order;
    import com.db.factor.order.SimpleFactor;
    import com.db.factormethod.pizza.Pizza;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 訂購披薩的類
     */
    public abstract class OrderPizza {
    
    
        public OrderPizza() {
            Pizza pizza = null;
            String type; //訂購披薩的型別
            do {
                type = getType();
                pizza = createPizza(type);
                //輸出Pizza的製作過程
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.bake();
            } while (true);
        }
    
        //定義一個抽象方法,createPizza,讓各個工廠類自己去實現
        public abstract Pizza createPizza(String type);
    
        //寫一個方法,可以獲取客戶希望訂購的Pizza種類
        private String getType() {
            try {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
                System.out.println("input pizza type:");
                String str = bufferedReader.readLine();
                return str;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
        }
    }
    
    
    package com.db.factormethod.order;
    
    import com.db.factormethod.pizza.LDCheesePizza;
    import com.db.factormethod.pizza.LDPepperPizza;
    import com.db.factormethod.pizza.Pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 倫敦訂購披薩的類
     */
    public class LDOrderPizza extends OrderPizza {
        @Override
        public Pizza createPizza(String type) {
            Pizza pizza = null;
            if (type.equals("cheese")) {
                pizza = new LDCheesePizza();
            } else if (type.equals("pepper")) {
                pizza = new LDPepperPizza();
            }
            return pizza;
        }
    }
    
    package com.db.factormethod.order;
    import com.db.factormethod.pizza.BJCheesePizza;
    import com.db.factormethod.pizza.BJPepperPizza;
    import com.db.factormethod.pizza.Pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 北京訂購披薩的類
     */
    public class BJOrderPizza extends OrderPizza{
    
        @Override
        public Pizza createPizza(String type) {
            Pizza pizza = null;
            if (type.equals("cheese")){
                pizza = new BJCheesePizza();
            }else if (type.equals("pepper")){
                pizza = new BJPepperPizza();
            }
            return pizza;
        }
    }
    
    package com.db.factormethod.order;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     */
    public class PizzaStore {
        public static void main(String[] args) {
            new BJOrderPizza();
        }
    }
    
  • 執行結果

input pizza type:
cheese
為北京的乳酪pizza準備原材料
北京乳酪披薩backing
北京乳酪披薩cutting
北京乳酪披薩backing
input pizza type:
pepper
為北京的胡椒披薩準備原材料
北京的胡椒披薩backing
北京的胡椒披薩cutting
北京的胡椒披薩backing

抽象工廠模式

抽象工廠模式

  • 抽象工廠模式,定義了一個interface用於建立相關或者有依賴關係的物件簇,而無需指明具體的類

  • 抽象工廠模式可以將簡單工廠模式和工廠方法模式進行整合

  • 從設計層面來看,抽象工廠模式就是對簡單工廠模式的改進(或者稱為進一步的抽象)

  • 將工廠抽象成兩層,AbsFactory(抽象工廠)和具體實現的工廠子類,程式設計師可以根據建立物件型別使用相應的工廠子類。這樣將單個的簡單工廠類變成了工廠簇,更加有利於程式碼的維護和擴充套件

  • 程式碼示例:

    package com.db.absfactory.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 將Pizza做成抽象類
     */
    public abstract class Pizza {
        protected String name; //準備
    
        //準備原材料,不同的披薩不一樣,因此.我們做成抽象方法
        public abstract void prepare();
    
        public void bake() {
            System.out.println(name + "backing");
        }
    
        public void cut() {
            System.out.println(name + "cutting");
        }
    
        //打包
        public void box() {
            System.out.println(name + "boxing");
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    }
    
    
    package com.db.absfactory.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 倫敦的胡椒披薩
     */
    public class LDPepperPizza extends Pizza {
        @Override
        public void prepare() {
            setName("倫敦的胡椒披薩");
            System.out.println("為倫敦的胡椒披薩準備原材料");
        }
    }
    
    
    package com.db.absfactory.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 倫敦的胡椒披薩
     */
    public class LDCheesePizza extends Pizza {
        @Override
        public void prepare() {
            setName("倫敦的胡椒披薩");
            System.out.println("為倫敦的胡椒披薩準備原材料");
        }
    }
    
    
    package com.db.absfactory.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     */
    public class BJPepperPizza extends Pizza {
        @Override
        public void prepare() {
            setName("北京的胡椒披薩");
            System.out.println("為北京的胡椒披薩準備原材料");
        }
    }
    
    package com.db.absfactory.pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     */
    public class BJCheesePizza extends Pizza {
        @Override
        public void prepare() {
            setName("北京乳酪披薩");
            System.out.println("為北京的乳酪pizza準備原材料");
        }
    }
    
    package com.db.absfactory.order;
    
    import com.db.absfactory.pizza.Pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 抽象工廠模式的抽象層(介面)
     */
    public interface IAbsFactory {
        //讓下面的工廠子類去具體實現
        public Pizza createPizza(String type);
    }
    
    package com.db.absfactory.order;
    
    import com.db.absfactory.pizza.BJCheesePizza;
    import com.db.absfactory.pizza.BJPepperPizza;
    import com.db.absfactory.pizza.Pizza;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 北京的工廠
     */
    public class BJFactor implements IAbsFactory {
        @Override
        public Pizza createPizza(String type) {
            System.out.println("使用抽象工廠模式");
            Pizza pizza = null;
            if (type.equals("cheese")){
                pizza = new BJCheesePizza();
            }else if(type.equals("pepper")){
                pizza = new BJPepperPizza();
            }
            return pizza;
        }
    }
    
    package com.db.absfactory.order;
    
    import com.db.absfactory.pizza.*;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     */
    public class LDFactor implements IAbsFactory{
        @Override
        public Pizza createPizza(String type) {
            System.out.println("使用抽象工廠模式");
            Pizza pizza = null;
            if (type.equals("cheese")){
                pizza = new LDCheesePizza();
            }else if(type.equals("pepper")){
                pizza = new LDPepperPizza();
            }
            return pizza;
        }
    }
    
    package com.db.absfactory.order;
    
    import com.db.absfactory.pizza.Pizza;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     * 訂購披薩的類
     */
    public class OrderPizza {
        IAbsFactory iAbsFactory;
    
        public OrderPizza(IAbsFactory iAbsFactory) {
            setiAbsFactory(iAbsFactory);
        }
    
        public void setiAbsFactory(IAbsFactory iAbsFactory) {
            this.iAbsFactory = iAbsFactory;
            String type = "";
            Pizza pizza = null;
            do {
                type = getType();
                pizza = iAbsFactory.createPizza(type);
                //輸出披薩的製作guoc
                if (pizza != null) {
                    pizza.prepare();
                    pizza.bake();
                    pizza.cut();
                    pizza.box();
                }else {
                    System.out.println("訂購失敗");
                }
            } while (true);
        }
    
        //寫一個方法,可以獲取客戶希望訂購的Pizza種類
        private String getType() {
            try {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
                System.out.println("input pizza type:");
                String str = bufferedReader.readLine();
                return str;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
        }
    
    }
    
    package com.db.absfactory.order;
    
    import com.sun.org.apache.bcel.internal.generic.NEW;
    
    /**
     * @author 通過程式看世界
     * @version 1.0
     */
    public class PizzaStore {
        public static void main(String[] args) {
            new OrderPizza(new BJFactor());
        }
    }
    
  • 執行結果

    input pizza type:
    pepper
    使用抽象工廠模式
    為北京的胡椒披薩準備原材料
    北京的胡椒披薩backing
    北京的胡椒披薩cutting
    北京的胡椒披薩boxing
    input pizza type:
    cheese
    使用抽象工廠模式
    為北京的乳酪pizza準備原材料
    北京乳酪披薩backing
    北京乳酪披薩cutting
    北京乳酪披薩boxing
    

JDK當中的工廠模式

Calendar原始碼分析

Calendar類當中的createCalendar方法就是採用了簡單工廠模式,根據傳輸的不同的aLocale 返回不同的Calendar例項

 private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale)
    {
       Calendar cal = null;
       if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                case "buddhist":
                cal = new BuddhistCalendar(zone, aLocale);
                    break;
                case "japanese":
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                    break;
                case "gregory":
                    cal = new GregorianCalendar(zone, aLocale);
                    break;
                }
            }
        }
        return cal;
    }

工廠模式的總結

  1. 工廠模式的意義
    1. 將例項化物件的程式碼提取出來,放到一個類當中進行統一管理和維護,達到和主專案的依賴關係的解耦合,從而提高專案的擴充套件性和維護性
  2. 三種工廠模式
    1. 簡單工廠模式
    2. 工廠方法模式
    3. 抽象工廠模式
  3. 設計模式的依賴抽象原則
    1. 建立物件例項的時候,不要直接new類,而是把這個new類的動作放到一個工廠的方法當中,並且返回,有的書上說,變數不要直接持有具體類的引用。
    2. 不要讓類繼承具體類,而是繼承抽象類或者實現介面
    3. 不要覆蓋基類中已經實現的方法