簡單工廠模式
看一個具體的需求
看一個披薩的項目:要便於披薩種類的擴展,要便於維護。
- 披薩的種類很多(比如GreekPizza、CheesePizza等);
- 披薩的制作有prepare,bake,cut,box;
- 完成披薩店訂購功能。
使用傳統的方式完成
//把Pizza類做成抽象類
public abstract class Pizza {
private 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;
}
}
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("給GreekPizza准備原材料");
}
}
public class CheessPizza extends Pizza {
@Override
public void prepare() {
System.out.println("給CheessPizza准備原材料");
}
}
public class OrderPizza {
//構造方法
public OrderPizza() {
Pizza pizza = null;
String orderType;//訂購披薩的類型
do {
orderType = getType();
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName("GreekPizza");
} else if (orderType.equals("cheess")) {
pizza = new CheessPizza();
pizza.setName("CheessPizza");
} else {
break;
}
//輸出pizza制作過程
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 = null;
str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
//相當於客戶端
public class OrderStore {
public static void main(String[] args) {
OrderPizza orderPizza = new OrderPizza();
}
}
傳統方式的優缺點:
- 優點是比較好理解,簡單易操作;
- 缺點是違反了設計模式的ocp原則,即對擴展開放,對修改關閉。即當我們給類增加新功能的時候,盡量不修改代碼,或者盡量少修改代碼;
- 比如這時我們要新增加一個Pizza的種類(Pepper披薩),我們需要做的修改較大。
改進的思路分析:
- 分析:修改代碼可以接受,但是如果我們在其它的地方也有創建Pizza的代碼,就意味着,也需要修改,而創建Pizza的代碼,往往有多處;
- 思路:把創建Pizza對象封裝到一個類中,這樣我們有新的Pizza種類時,只需要修改該類就可,其它有創建到Pizza對象的代碼就不需要修改了(使用簡單工廠模式)。
簡單工廠模式
簡單工廠模式是屬於創建型模式,是工廠模式的一種。簡單工廠模式是由一個工廠對象決定創建出哪一種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式。
簡單工廠模式:定義了一個創建對象的類,由這個類來封裝實例化對象的行為。
在軟件開發中,當我們會用到大量的創建某種、某類或者謀批對象時,就會使用到工廠模式。
簡單工廠模式的設計方案:定義一個可以實例化Pizza對象的類,封裝創建對象的代碼。
//簡單工廠類
public class SimpleFactory {
//簡單工廠模式,也叫靜態工廠模式,可以用static修飾該方法
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName("GreekPizza");
} else if (orderType.equals("cheess")) {
pizza = new CheessPizza();
pizza.setName("CheessPizza");
}
//輸出pizza制作過程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
public class OrderPizza2 {
//定義一個簡單工廠對象
SimpleFactory simpleFactory;
//構造器
public OrderPizza2(SimpleFactory simpleFactory) {
setFactory(simpleFactory);
}
Pizza pizza = null;
public void setFactory(SimpleFactory simpleFactory) {
String orderType = "";//用戶輸入的
this.simpleFactory = simpleFactory;//設置簡單工廠對象
do {
orderType = getType();
pizza = this.simpleFactory.createPizza(orderType);
//輸出pizza制作過程
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 type:");
String str = null;
str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
//相當於客戶端
public class OrderStore {
public static void main(String[] args) {
OrderPizza2 orderPizza = new OrderPizza2(new SimpleFactory());
}
}
工廠方法模式
披薩項目新的需求:客戶在點披薩時,可以點不同口味的披薩,比如“北京的奶酪披薩”、“北京的胡椒披薩”或者是“倫敦的奶酪披薩”、“倫敦的胡椒披薩”。
思路一:使用簡單工廠模式,創建不同的簡單工廠類,比如BJPizzaSimpleFactory、LDPizzzaSimpleFactory等等,從當前這個案例來說,也是可以的,但是考慮到項目的規模,以及軟件的可維護性 、可擴展性並不是特別好。
思路二:使用工廠方法模式。將披薩項目的實例化功能抽象成抽象方法,在不同口味點餐子類中具體實現。
工廠方法模式定義了一個創建對象的抽象方法,由子類決定要實例化的類。工廠方法模式將對象的實例化推遲到子類。
//把Pizza類做成抽象類
public abstract class Pizza {
private 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;
}
}
public class BJCheessPizza extends Pizza {
@Override
public void prepare() {
setName("北京的CheessPizza");
System.out.println(" 北京的CheessPizza 准備原材料");
}
}
public class BJPepperPizza extends Pizza {
@Override
public void prepare() {
setName("北京的Pepper");
System.out.println(" 北京的Pepper 准備原材料");
}
}
public class LDCheessPizza extends Pizza {
@Override
public void prepare() {
setName("倫敦的CheessPizza");
System.out.println(" 倫敦的CheessPizza 准備原材料");
}
}
public class LDPepperPizza extends Pizza {
@Override
public void prepare() {
setName("倫敦的Pepper");
System.out.println(" 倫敦的Pepper 准備原材料");
}
}
public abstract class OrderPizza {
//構造方法
public OrderPizza() {
Pizza pizza = null;
String orderType;//訂購披薩的類型
do {
orderType = getType();
//調用方法
pizza = creatPizza(orderType);
//輸出pizza制作過程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
//定義一個抽象方法,讓各個工廠子類自己實現
abstract Pizza creatPizza(String orderType);
//寫一個方法,可以獲取客戶希望訂購的披薩種類
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String str = null;
str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
public class BJOrderPizza extends OrderPizza {
@Override
Pizza creatPizza(String orderType) {
Pizza pizza=null;
if (orderType.equals("Cheess")){
pizza=new BJCheessPizza();
}else if(orderType.equals("Pepper")){
pizza=new BJPepperPizza();
}
return pizza;
}
}
public class LDOrderPizza extends OrderPizza {
@Override
Pizza creatPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("Cheess")) {
pizza = new LDCheessPizza();
} else if (orderType.equals("Pepper")) {
pizza = new LDPepperPizza();
}
return pizza;
}
}
//披薩店
public class PizzaStore {
public static void main(String[] args) {
new BJOrderPizza();//創建北京各種口味的披薩
new LDOrderPizza();//創建倫敦各種口味的披薩
}
}
抽象工廠模式
抽象工廠模式:定義了一個interface用於創建相關或有依賴關系的對象簇,而無需指明具體的類。
抽線工廠模式可以將簡單工廠模式和工廠方法模式進行整合。
從設計層面看,抽象工廠模式就是對簡單工廠模式的改進(或者 稱為進一步的抽象)。
將工廠抽象成兩層,AbsFactory(抽象工廠)具體實現的工廠子類。程序員可以根據創建對象類型使用對應的工廠子類。這樣將單個的簡單工廠類變成了工廠簇,更利於代碼的維護。
//一個抽象工廠模式的抽象層(接口)
public interface AbsFactory {
//讓下面的工廠子類來具體實現
Pizza createPizza(String orderType);
}
//這是一個工廠子類
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("Cheess")) {
pizza = new BJCheessPizza();
}
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("Cheess")){
pizza=new LDCheessPizza();
}if (orderType.equals("Pepper")){
pizza=new LDPepperPizza();
}
return pizza;
}
}
public class OrderPizza {
AbsFactory factory;
//構造器
public OrderPizza(AbsFactory factory) {
setFactory(factory);
}
private void setFactory(AbsFactory factory) {
Pizza pizza = null;
String orderType = "";//用戶輸入
this.factory = factory;
do {
orderType = getType();
//factory可能是北京的工廠子類,也可能是倫敦的工廠子類
pizza = factory.createPizza(orderType);
if (pizza != null) {
pizza.prepare();
pizza.bake();
pizza.box();
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 = null;
str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
public class PizzaStore {
public static void main(String[] args) {
new OrderPizza(new BJFactory());
new OrderPizza(new LDFactory());
}
}
工廠模式小結
工廠模式的意義:將實例化對象的代碼提取出來,放到一個類中統一管理和維護,達到和主項目的依賴關系的解耦,從而提高項目的擴展和維護性。
三種工廠模式:簡單工廠模式、工廠方法模式、抽象工廠模式。
設計模式的依賴抽象原則:
- 創建對象實例時,不要直接new類,而是把這個new類的動作放在一個工廠的方法中,並返回。有的書上說,變量不要直接持有具體類的引用;
- 不要讓類繼承具體類,而是繼承抽象類或者是實現interface(接口);
- 不要覆蓋基類中已經實現的方法。