1. 程式人生 > 其它 >【設計模式從入門到精通】02-工廠模式

【設計模式從入門到精通】02-工廠模式

工廠模式

筆記來源:尚矽谷Java設計模式(圖解+框架原始碼剖析)

目錄

工廠模式

看一個具體的需求

看一個披薩的專案:要便於披薩種類的擴充套件,要便於維護

  • 1)披薩的種類很多(比如 GreekPizz、CheesePizz 等)
  • 2)披薩的製作有 prepare、bake、cut、box
  • 3)完成披薩店訂購功能

傳統方式

UML 類圖

核心程式碼

public abstract class Pizza {
    protected String name;

    public void setName(String name) {
        this.name = 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 class GreekPizza extends Pizza {
    @Override
    public void prepare() {
        setName("GreekPizza");
        System.out.println(name + " preparing...");
    }
}

// 乳酪披薩
public class CheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("CheesePizza");
        System.out.println(name + " preparing...");
    }
}

public class OrderPizza {
    public OrderPizza() {
        Pizza pizza = null;
        String orderType;
        do {
            orderType = getType();
            if ("cheese".equals(orderType)) {
                pizza = new CheesePizza();
            } else if ("greek".equals(orderType)) {
                pizza = new GreekPizza();
            } else {
                System.out.println("輸入型別錯誤,程式退出");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }

    private String getType() {
        System.out.println("請輸入披薩型別:");
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        try {
            return reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

傳統方式優缺點

  • 1)優點是比較好理解,簡單易操作
  • 2)缺點是違反了設計模式的 OCP 原則,即對擴充套件開放,對修改關閉。即當我們給類增加新能的時候,儘量不修改程式碼,或者儘可能少修改程式碼
  • 3)比如我們這時要新增加一個Pizza的種類(Cheese技薩),我們需要做如下修改
// 胡椒披薩
public class PepperPizza extends Pizza {
    @Override
    public void prepare() {
        setName("PepperPizza");
        System.out.println(name + " preparing...");
    }
}

public class OrderPizza {
    public OrderPizza() {
        // ...
        else if ("pepper".equals(orderType)) {
            pizza = new PepperPizza();
        } 
        // ...
    }
    // ...
}

改進的思路分析

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

1、簡單工廠模式

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

UML 類圖

核心程式碼

public class PizzaFactory {
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        switch (orderType) {
            case "cheese":
                pizza = new CheesePizza();
                break;
            case "greek":
                pizza = new GreekPizza();
                break;
            case "pepper":
                pizza = new PepperPizza();
                break;
            default:
                break;
        }
        return pizza;
    }
}

public class OrderPizza {
    private PizzaFactory pizzaFactory;

    public OrderPizza(PizzaFactory pizzaFactory) {
        this.pizzaFactory = pizzaFactory;
        orderPizza();
    }

    public void orderPizza() {
        Pizza pizza = null;
        do {
            pizza = pizzaFactory.createPizza(getType());
            if (pizza == null) {
                System.out.println("Failed to Order Pizza");
            } else {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
        } while (true);
    }
    // ...
}

2、靜態工廠模式

靜態工廠模式也是簡單工廠模式的一種,只是將工廠方法改為靜態方法

UML 類圖

核心程式碼

public class PizzaFactory {
    public static Pizza createPizza(String orderType) {
        // ...
    }
}

public class OrderPizza {
    public OrderPizza() {
        Pizza pizza;
        do {
            pizza = PizzaFactory.createPizza(getType());
            // ...
        } while (true);
    }

3、工廠方法模式

工廠方法模式設計方案:將披薩專案的例項化功能抽象成抽象方法,在不同的口味點餐子類中具體實現

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

看一個新的需求

披薩專案新的需求:客戶在點披薩時,可以點不同口味的披薩,比如北京的乳酪 Pizza、北京的胡椒 Pizza 或者是倫敦的乳酪 Pizza、倫敦的胡椒 Pizza

思路1:使用簡單工廠模式,建立不同的簡單工廠類,比如 BJPizzaFactory、LDPizzaFactory 等等。從當前這個案例來說,也是可以的,但是考慮到專案的規模,以及軟體的可維護性、可擴充套件性並不是特別好

思路2:使用工廠方法模式

UML 類圖

核心程式碼

public abstract class OrderPizza {

    public void orderPizza() {
        Pizza pizza = null;
        do {
            pizza = createPizza(getType());
            if (pizza == null) {
                System.out.println("Failed to Order Pizza");
            } else {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
        } while (true);
    }

    public abstract Pizza createPizza(String orderType);
     
    // ...
}

public class LDOrderPizza extends OrderPizza {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        switch (orderType) {
            case "cheese":
                pizza = new LDCheesePizza();
                break;
            case "pepper":
                pizza = new LDPepperPizza();
                break;
            default:
                break;
        }
        return pizza;
    }
}

public class BJOrderPizza extends OrderPizza {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        switch (orderType) {
            case "cheese":
                pizza = new BJCheesePizza();
                break;
            case "pepper":
                pizza = new BJPepperPizza();
                break;
            default:
                break;
        }
        return pizza;
    }
}

4、抽象工廠模式

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

UML 類圖

核心程式碼

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

public class BJPizzaFactory implements AbsPizzaFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        switch (orderType) {
            case "cheese":
                pizza = new BJCheesePizza();
                break;
            case "pepper":
                pizza = new BJPepperPizza();
                break;
            default:
                break;
        }
        return pizza;
    }
}

public class LDPizzaFactory implements AbsPizzaFactory {
    @Override
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        switch (orderType) {
            case "cheese":
                pizza = new LDCheesePizza();
                break;
            case "pepper":
                pizza = new LDPepperPizza();
                break;
            default:
                break;
        }
        return pizza;
    }
}

JDK 原始碼分析

JDK 中的 Calendar 類中,就使用了簡單工廠模式

小結

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