今天來學習23種設計模式的第二種,工廠方法模式,同時也是Java 中最常用的設計模式之一。
概念:
定義一個創建產品對象的工廠接口,將產品對象的實際創建工作推遲到具體子工廠類當中。這滿足創建型模式中所要求的“創建與使用相分離”的特點。
我們把被創建的對象稱爲“產品”,把創建產品的對象稱爲“工廠”。如果要創建的產品不多,只要一個工廠類就可以完成,這種模式叫“簡單工廠模式”,它不屬於 GOF 的 23 種經典設計模式,它的缺點是增加新產品時會違背“開閉原則”。
本文介紹的“工廠方法模式”是對簡單工廠模式的進一步抽象化,其好處是可以使系統在不修改原來代碼的情況下引進新的產品,即滿足開閉原則。
特點:
- 用戶只需要知道具體工廠的名稱就可得到所要的產品,無須知道產品的具體創建過程。
- 在系統增加新的產品時只需要添加具體產品類和對應的具體工廠類,無須對原工廠進行任何修改,滿足開閉原則。
工廠方法的主要角色:
- 抽象工廠(Abstract Factory):提供了創建產品的接口,調用者通過它訪問具體工廠的工廠方法
new Product()
來創建產品。 - 具體工廠(Concrete Factory):主要是實現抽象工廠中的抽象方法,完成具體產品的創建。
- 抽象產品(Product):定義了產品的規範,描述了產品的主要特性和功能。
- 具體產品(Concrete Product):實現了抽象產品角色所定義的接口,由具體工廠來創建,它同具體工廠之間一一對應。
類圖分析:
核心代碼:
- 圖形的抽象類
package cn.ppdxzz.factorymethod.graph;
/**
* Description:圖形抽象類
*
* @Date: 2020/3/4 17:51
* @Author: PeiChen
*/
public abstract class Graph {
//開始繪製
public abstract void startDraw();
//結束繪製
public abstract void finishDraw();
}
- 圖形的具體實現類(這裏僅列舉小萬、小李繪製圓形的實現,重在這種設計思想的領悟)
package cn.ppdxzz.factorymethod.graph;
/**
* Description:小萬繪製圓形
*
* @Date: 2020/3/4 18:03
* @Author: PeiChen
*/
public class WanCircle extends Graph {
@Override
public void startDraw() {
System.out.println("小萬開始繪製圓形...");
}
@Override
public void finishDraw() {
System.out.println("小萬結束繪製圓形...");
System.out.println("-------------------");
}
}
package cn.ppdxzz.factorymethod.graph;
/**
* Description:小李繪製圓形
*
* @Date: 2020/3/4 18:08
* @Author: PeiChen
*/
public class LiCircle extends Graph {
@Override
public void startDraw() {
System.out.println("小李開始繪製圓形...");
}
@Override
public void finishDraw() {
System.out.println("小李結束繪製圓形...");
System.out.println("-------------------");
}
}
- 將繪製圖形的實例化功能抽象爲抽象方法,在不同的繪製者的子類中具體實現。
package cn.ppdxzz.factorymethod.draw;
import cn.ppdxzz.factorymethod.graph.Graph;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Description:繪製圖形的工廠類
*
* @Date: 2020/3/4 18:14
* @Author: PeiChen
*/
public abstract class DrawGraph {
//定義一個繪圖抽象方法,讓各個工廠子類自己實現需要繪製什麼圖形
abstract Graph createGraph(String createType);
//構造方法
public DrawGraph() {
Graph graph = null;
String drawType;
do {
drawType = getType();
//抽象方法,由工廠子類完成圖形的繪製
graph = createGraph(drawType);
if (graph != null) {
graph.startDraw();
graph.finishDraw();
}else {
System.out.println("圖形輸入有誤,已退出!");
break;
}
}while (true);
}
//獲取繪製者輸入繪製的圖形形狀
private String getType() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("請輸入繪製的圖形:");
try {
String str = reader.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
- 小萬這個繪製者的具體實現類。
package cn.ppdxzz.factorymethod.draw;
import cn.ppdxzz.factorymethod.graph.Graph;
import cn.ppdxzz.factorymethod.graph.WanCircle;
import cn.ppdxzz.factorymethod.graph.WanRectangle;
import cn.ppdxzz.factorymethod.graph.WanTriangle;
/**
* Description:小萬繪製的圖形
*
* @Date: 2020/3/4 19:28
* @Author: PeiChen
*/
public class DrawWanGraph extends DrawGraph {
@Override
Graph createGraph(String createType) {
Graph graph = null;
if ("circle".equals(createType)) {
graph = new WanCircle();
}else if ("rectangle".equals(createType)) {
graph = new WanRectangle();
}else if ("triangle".equals(createType)){
graph = new WanTriangle();
}
return graph;
}
}
- 小李這個繪製者的具體實現類。
package cn.ppdxzz.factorymethod.draw;
import cn.ppdxzz.factorymethod.graph.Graph;
import cn.ppdxzz.factorymethod.graph.LiCircle;
import cn.ppdxzz.factorymethod.graph.LiRectangle;
/**
* Description:小李繪製的圖形
*
* @Date: 2020/3/4 19:20
* @Author: PeiChen
*/
public class DrawLiGraph extends DrawGraph {
@Override
Graph createGraph(String createType) {
Graph graph = null;
if ("circle".equals(createType)) {
graph = new LiCircle();
}else if ("rectangle".equals(createType)){
graph = new LiRectangle();
}
return graph;
}
}
總結:
工廠方法模式非常符合“開閉原則”,當需要增加一個新的產品時,我們只需要增加一個具體的產品類和與之對應的具體工廠即可,無須修改原有系統。同時在工廠方法模式中用戶只需要知道生產產品的具體工廠即可,無須關係產品的創建過程,甚至連具體的產品類名稱都不需要知道。
雖然他很好的符合了“開閉原則”,但是由於每新增一個新產品時就需要增加兩個類,這樣勢必會導致系統的複雜度增加。
工廠方法模式就講解到這裏,後面我們將會引入另一種設計模式——抽象工廠模式。