設計模式之工廠模式

工廠模式

案例說明:

一個披薩的項目:要便於披薩種類的擴展,要便於維護

  1. 披薩的種類很多(比如 GreekPizz、CheesePizz 等)
  2. 披薩的製作有 prepare,bake, cut, box
  3. 完成披薩店訂購功能
案例分別使用四種方式去實現:
點擊跳轉

1.傳統方法
2.簡單工廠模式
3.工廠方法模式
4.抽象工廠模式

利用傳統方法完成此案例:

設計思路:

1.設計一個抽象Pizza類,把準備原材料的方法做成抽象方法
2.烹飪 裁剪 打包等方法在抽象類中實現
3.設計GreekPizz CheesePizz 繼承抽象類
4.設計訂單類,創建訂單時需要得到 pizza 的名稱,通過判斷不同名稱,產生不同pizza對象。
5.編寫商店類,產生訂單。

代碼實現:

Pizza抽象類:


/**
 * @author 孫一鳴 on 2020/2/5
 */

public abstract class Pizza {
   protected String name;

   //準備原材料,不同披薩原材料不同
   public  abstract void prepare();

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

Cheese Pizza類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class CheesePizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("給製作奶酪披薩準備原材料...");
    }
}

Greek Pizza類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class GreekPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("給製作希臘披薩準備原材料...");
    }
}

訂單類:


/**
 * @author 孫一鳴 on 2020/2/5
 */
public class OrderPizza {
    public OrderPizza() {
        Pizza pizza = null;
        String orderName;
        do {
            orderName = gettype();
            if (orderName.equals("greek")) {
                pizza = new GreekPizza();
                pizza.setName("希臘披薩 ");
            } else if (orderName.equals("cheese")) {
                pizza = new CheesePizza();
                pizza.setName("奶酪披薩 ");
            } 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 type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

超市類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza();
    }
}

結果截圖:

在這裏插入圖片描述

傳統的方式的優缺點:
  1. 優點是比較好理解,簡單易操作。
  2. 缺點是違反了設計模式的ocp原則,即對擴展開放,對修改關閉。即當我們給類增加新功能的時候,儘量不修改代碼,或者儘可能少修改代碼.
  3. 比如我們這時要新增加一個Pizza的種類(Pepper披薩),我們需要做如下修改.

新加胡椒披薩類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class PepperPizza extends Pizza {
    @Override
    public void prepare() {
        System.out.println("爲胡椒披薩準備原材料...");
    }
}

訂單類修改:

else if (orderName.equals("pepper")){
                pizza = new PepperPizza();
                pizza.setName("新加胡椒披薩 ");
            }
改進傳統模式分析:

分析:修改代碼可以接受,但是如果我們在其它的地方也有創建Pizza的代碼,就意味
着,也需要修改,而創建Pizza的代碼,往往有多處
思路:把創建Pizza對象封裝到一個類中,這樣我們有新的Pizza種類時,只需要修改該類就可,其它有創建到Pizza對象的代碼就不需要修改了.-> 簡單工廠模式

簡單工廠模式:

基本介紹:

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

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class SimpleFactory {
    public Pizza createPizza(String orderName){
        Pizza pizza = null;
        System.out.println("使用簡單工廠模式..");
        if (orderName.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName("希臘披薩 ");
        } else if (orderName.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName("奶酪披薩 ");
        }else if (orderName.equals("pepper")){
            pizza = new PepperPizza();
            pizza.setName("新加胡椒披薩 ");
        }
        return pizza;
    }
}

訂單類:


/**
 * @author 孫一鳴 on 2020/2/5
 */
public class OrderPizza {


    //定義一個簡單工廠對象
    SimpleFactory simpleFactory;

    Pizza pizza =null;

    //構造器
    public OrderPizza(SimpleFactory simpleFactory) {
        setFactory(simpleFactory);
    }

    public void setFactory(SimpleFactory simpleFactory){
        String orderName="";
        do {
            orderName = gettype();
            pizza = simpleFactory.createPizza(orderName);
            if (pizza !=null){
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.cut();
            }else{
                System.out.println("訂單錯誤....");
            }
        }while (true);
    }
    private String gettype() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

看一個新的需求
披薩項目新的需求:客戶在點披薩時,可以點不同口味的披薩,比如 北京的奶酪pizza、北京的胡椒pizza 或者是倫敦的奶酪pizza、倫敦的胡椒pizza。
思路1
使用簡單工廠模式,創建不同的簡單工廠類,比如BJPizzaSimpleFactory、
LDPizzaSimpleFactory 等等.從當前這個案例來說,也是可以的,但是考慮到項目的
規模,以及軟件的可維護性、可擴展性並不是特別好
思路2
使用工廠方法模式

工廠方法模式

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

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class PizzaStore {
    public static void main(String[] args) {
        new BJOrderPizza();
    }
}

北京披薩訂單類繼承抽象類:

先去運行父類的構造方法

/**
 * @author 孫一鳴 on 2020/2/5
 */
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;
    }
}

倫敦披薩訂單類繼承父類抽象類:


/**
 * @author 孫一鳴 on 2020/2/5
 */
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;
    }
}

披薩訂單抽象類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public abstract class OrderPizza {
    abstract  Pizza createPizza(String orderType);

    public OrderPizza(){
        Pizza pizza=null;
        String orderType;
        do {
            orderType =gettype();

            pizza=createPizza(orderType);//抽象方法,由工廠子類實現
            //輸出製作過程
            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 type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}


北京奶酪披薩類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京奶酪披薩");
        System.out.println("給北京奶酪披薩準備原料...");
    }
}

北京胡椒披薩類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class BJPepperPizza  extends Pizza{
    @Override
    public void prepare() {
        setName("北京胡椒披薩");
        System.out.println("給北京胡椒披薩準備原料...");
    }
}

倫敦奶酪披薩類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class LDCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("倫敦奶酪披薩");
        System.out.println("給倫敦奶酪披薩準備原料...");
    }
}

倫敦胡椒披薩類:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class LDPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("倫敦胡椒披薩");
        System.out.println("給倫敦胡椒披薩準備原料...");
    }
}


抽象工廠模式

基本介紹:

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

在這裏插入圖片描述
抽象工廠模式的抽象層 接口

//一個抽象工廠模式的抽象層 接口
public interface AbcFactory {
    //讓下面的工廠子類具體實現
    public Pizza createPizza(String oederType);
}

北京披薩工廠:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class BJFactory implements AbcFactory{
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("這是抽象工廠模式..");
       Pizza pizza=null;
        if(orderType.equals("cheese")){
            pizza=new BJCheesePizza();
        }else  if (orderType.equals("pepper")){
            pizza =new BJPepperPizza();
        }
        return pizza;

    }
}

倫敦披薩工廠:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class LDFactory implements AbcFactory{
    @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;

    }
}

披薩訂單 :

/**
 * @author 孫一鳴 on 2020/2/5
 */
public  class OrderPizza {
    AbcFactory factory;

    public OrderPizza(AbcFactory factory) {
       setFactory(factory);
    }



    public void setFactory(AbcFactory factory){
        Pizza pizza=null;
        String orderName="";
        this.factory = factory;
        do {
            orderName = gettype();
            pizza = factory.createPizza(orderName);
            if (pizza !=null){
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.cut();
            }else{
                System.out.println("訂單錯誤....");
                break;
            }
        }while (true);
    }

    private String gettype() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

披薩商店:

/**
 * @author 孫一鳴 on 2020/2/5
 */
public class PizzaStore {
    public static void main(String[] args) {
        //new OrderPizza(new BJFactory());
        new OrderPizza(new LDFactory());
    }
}

工廠模式小結

  1. 工廠模式的意義
    將實例化對象的代碼提取出來,放到一個類中統一管理和維護,達到和主項目的
    依賴關係的解耦。從而提高項目的擴展和維護性。
  2. 三種工廠模式 (簡單工廠模式、工廠方法模式、抽象工廠模式)
  3. 設計模式的依賴抽象原則
     創建對象實例時,不要直接 new 類, 而是把這個new 類的動作放在一個工廠的方法
    中,並返回。有的書上說,變量不要直接持有具體類的引用。
     不要讓類繼承具體類,而是繼承抽象類或者是實現interface(接口)
     不要覆蓋基類中已經實現的方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章