【設計模式從入門到精通】02-工廠模式
阿新 • • 發佈:2021-10-16
工廠模式
目錄
工廠模式
看一個具體的需求
看一個披薩的專案:要便於披薩種類的擴充套件,要便於維護
- 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(介面)
- 不要覆蓋基類中已經實現的方法