我以訂披薩爲例,給女朋友詳細講了Java設計模式的3種工廠模式

摘要:工廠模式是將實例化對象的代碼提取出來,放到一個類中統一管理和維護,達到和主項目的依賴關係的解耦。從而提高項目的擴展和維護性。

本文分享自華爲雲社區《【Java設計模式】用 披薩訂購案例 詳細講解三種工廠模式》,作者: 我是一棵捲心菜。

一、使用傳統方法

類圖

步驟概括

步驟一:創建一個Pizza抽象類

 public abstract class Pizza {
    public String name;
    public abstract void prepare();
    public void bake() {
        System.out.println(name + " baking");
    }
    public void cut() {
        System.out.println(name + " cutting");
    }
    public void box() {
        System.out.println(name + " boxing");
    }
    public void setName(String name) {
        this.name = name;
    }
}

分析: 這個類用來代表製作披薩的整個流程:準備階段prepare()烘烤階段bake()切割階段cut()打包階段box() ,假設各個披薩的準備階段需要的材料不一樣,所以把準備階段定義爲一個抽象方法 ,其它三個階段都一樣。

步驟二:創建兩個披薩類

public class CheesePizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("奶酪披薩正在準備中");
    }
}

分析: 這個類代表奶酪披薩,簡單重寫一下準備階段

 public class BeefPizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("牛肉披薩正在準備中");
    }
}

分析: 這個類代表牛肉披薩,也簡單重寫一下準備階段

步驟三:制定訂購披薩類

 public class OrderPizza {
    public OrderPizza() {
        Pizza pizza = null;
        do {
            String pizzaType = getType();
            if ("cheese".equalsIgnoreCase(pizzaType)) {
                 pizza = new CheesePizza();
                 pizza.setName("cheese");
            } else if ("beef".equalsIgnoreCase(pizzaType)) {
                pizza = new BeefPizza();
                pizza.setName("beef");
            } else {
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }
    // 寫一個方法,可以獲取希望訂購的披薩種類
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 種類:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

分析: 慢慢看代碼,可以明白,訂購披薩的邏輯代碼寫在了該類的構造器中,getType()方法是用來獲取希望訂購的披薩種類。但是,如果我們需要添加新的披薩,就需要從這個類中繼續添加相應的邏輯語句,從而修改了訂購披薩的這個類,就違反了OCP原則

步驟四:創建運行類

 public class PizzaStore {
    public static void main(String[] args) {
       new OrderPizza();
    }
}

運行結果:

優缺點分析

  • 優點:比較好理解,簡單易操作
  • 缺點:違反了設計模式的ocp原則,即對擴展開放,對修改關閉。即當我們給類增加新功能的時候,儘量不修改代碼,或者儘可能少修改代碼

二、使用簡單工廠

類圖

基本介紹

  • 簡單工廠模式是屬於創建型模式,是工廠模式的一種。簡單工廠模式是由一個工廠對象決定創建出哪一種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式
  • 簡單工廠模式定義了一個創建對象的類,由這個類來封裝實例化對象的行爲(代碼)
  • 在軟件開發中,當我們會用到大量的創建某種、某類或者某批對象時,就會使用到工廠模式

步驟概括

步驟一:創建簡單工廠

public class SimpleFactory {
    public static Pizza createPizza2(String orderType) {
        Pizza pizza = null;
        if ("beef".equalsIgnoreCase(orderType)) {
            pizza = new BeefPizza();
            pizza.setName(" beef ");
        } else if ("cheese".equalsIgnoreCase(orderType)) {
            pizza = new CheesePizza();
            pizza.setName("cheese");
        }
        return pizza;
    }
}

分析: 簡單工廠又叫做靜態工廠,我們寫一個靜態方法,可以方便後面代碼的調用,這裏用到的類,跟用傳統方法用到的類一樣,沒有改變

步驟二:制定訂購披薩類

public class OrderPizza2 {
    public OrderPizza2() {
        do {
            String orderType = getType();
            Pizza pizza = SimpleFactory.createPizza2(orderType);
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println(" 訂購披薩失敗 ");
                break;
            }
        } while (true);
    }
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 種類:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

分析: 該類的構造器中用到了簡單工廠類SimpleFactory,這樣,我們就不需要在訂購披薩這一行爲中去寫增加新的披薩的代碼了,而是從工廠中寫添加新的披薩的代碼,就不用再改動這個類。

運行結果:

優點分析

  • 使用簡單工廠模式來創建對象,更加的方便靈活,不需要修改訂購披薩的邏輯

三、使用工廠方法

新的需求

客戶在點披薩時,可以點不同口味的披薩,比如 北京的奶酪pizza、北京的胡椒pizza 或者是倫敦的奶酪pizza、倫敦的胡椒pizza

類圖

基本介紹

  • 工廠方法模式設計方案:將披薩項目的實例化功能抽象成抽象方法,在不同的口味點餐子類中具體實現。
  • 工廠方法模式:定義了一個創建對象的抽象方法,由子類決定要實例化的類。工廠方法模式將對象的實例化推遲到子類。

步驟概括

步驟一:創建四個披薩類

public class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println("北京的奶酪pizza 準備原材料");
    }
}

分析: Pizza類跟上面的代碼一樣,我就沒有再次寫了。此類是用來創建北京的奶酪口味的披薩

public class BJPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京的胡椒pizza");
        System.out.println("北京的胡椒pizza 準備原材料");
    }
}

分析: 此類是用來創建北京的辣椒口味的披薩

public class LDCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("倫敦的奶酪pizza");
        System.out.println("倫敦的奶酪pizza 準備原材料");
    }
}

分析: 此類是用來創建倫敦的奶酪口味的披薩

public class LDPepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("倫敦的胡椒pizza");
        System.out.println("倫敦的胡椒pizza 準備原材料");
    }
}

分析: 此類是用來創建倫敦的辣椒口味的披薩

步驟二:創建訂購披薩抽象類

public abstract class OrderPizza {
    abstract Pizza createPizza(String orderType);
    public OrderPizza() {
        do {
            String orderType = getType();
            Pizza pizza = createPizza(orderType); //抽象方法,由工廠子類完成
            if (pizza == null){
                System.out.println("訂購披薩失敗");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 種類:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

分析: 此類中定義一個抽象方法createPizza(), 讓各個工廠子類自己實現,構造器中寫訂購披薩的代碼邏輯;getType()方法跟原來的沒有區別。

public class BJOrderPizza extends OrderPizza {
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

分析: 此類用來繼承OrderPizza類,成爲北京地區的訂購披薩分銷商

public class LDOrderPizza extends OrderPizza {
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

分析: 此類也用來繼承OrderPizza類,成爲倫敦地區的訂購披薩分銷商

步驟三:創建運行類

public class PizzaStore {
    public static void main(String[] args) {
        String loc = "beijing";
        if (loc.equals("beijing")) {
            new BJOrderPizza();
        } else {
            new LDOrderPizza();
        }
    }
}

分析: 假設就是買北京地區的披薩

運行結果:

四、使用抽象工廠

類圖

基本介紹

  • 抽象工廠模式定義了一個interface用於創建相關或有依賴關係的對象簇,而無需指明具體的類
  • 抽象工廠模式可以將簡單工廠模式和工廠方法模式進行整合
  • 從設計層面看,抽象工廠模式就是對簡單工廠模式的改進(或者稱爲進一步的抽象)
  • 將工廠抽象成兩層,AbsFactory(抽象工廠) 和 具體實現的工廠子類。程序員可以根據創建對象類型使用對應的工廠子類。這樣將單個的簡單工廠類變成了工廠簇,更利於代碼的維護和擴展。

步驟概括

步驟一:創建總工廠接口

public interface AbsFactory {
    public Pizza createPizza(String orderType);
}

分析: 此類是用來讓下面的工廠子類來具體實現

步驟二:創建分工廠

public class BJFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if(orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")){
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

分析: 這是工廠子類,用來製作北京的披薩

public class LDFactory implements AbsFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}

分析: 這是工廠子類,用來製作倫敦的披薩

步驟三:創建訂購類

public class OrderPizza {
    private AbsFactory factory;
    public OrderPizza(AbsFactory factory) {
        setFactory(factory);
    }
    private void setFactory(AbsFactory factory) {
        do {
            this.factory = factory;
            String orderType = getType();
            // factory 可能是北京的工廠子類,也可能是倫敦的工廠子類
            Pizza pizza = factory.createPizza(orderType);
            if (pizza == null) { 
                System.out.println("訂購失敗");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }   
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 種類:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

分析: Pizza pizza = factory.createPizza(orderType);這一語句主要運用的是java基礎裏面的多態,具體的實現功能交給實現其接口的子類

步驟四:創建運行類

public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza(new LDFactory());
    }
}

分析: 假設買的是倫敦地區的披薩

運行結果:

總結

1、工廠模式的意義:

將實例化對象的代碼提取出來,放到一個類中統一管理和維護,達到和主項目的依賴關係的解耦。從而提高項目的擴展和維護性。

2、三種工廠模式 (簡單工廠模式、工廠方法模式、抽象工廠模式)

3、設計模式的依賴抽象原則

創建對象實例時,不要直接 new 類, 而是把這個new 類的動作放在一個工廠的方法中,並返回
不要讓類繼承具體類,而是繼承抽象類或者是實現interface(接口)
不要覆蓋基類中已經實現的方法。

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

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