你確定會用工廠方法模式嗎?

今天來學習23種設計模式的第二種,工廠方法模式,同時也是Java 中最常用的設計模式之一。

概念:

定義一個創建產品對象的工廠接口,將產品對象的實際創建工作推遲到具體子工廠類當中。這滿足創建型模式中所要求的“創建與使用相分離”的特點。

我們把被創建的對象稱爲“產品”,把創建產品的對象稱爲“工廠”。如果要創建的產品不多,只要一個工廠類就可以完成,這種模式叫“簡單工廠模式”,它不屬於 GOF 的 23 種經典設計模式,它的缺點是增加新產品時會違背“開閉原則”。

本文介紹的“工廠方法模式”是對簡單工廠模式的進一步抽象化,其好處是可以使系統在不修改原來代碼的情況下引進新的產品,即滿足開閉原則。

特點:
  • 用戶只需要知道具體工廠的名稱就可得到所要的產品,無須知道產品的具體創建過程。
  • 在系統增加新的產品時只需要添加具體產品類和對應的具體工廠類,無須對原工廠進行任何修改,滿足開閉原則。
工廠方法的主要角色:
  • 抽象工廠(Abstract Factory):提供了創建產品的接口,調用者通過它訪問具體工廠的工廠方法 new Product() 來創建產品。
  • 具體工廠(Concrete Factory):主要是實現抽象工廠中的抽象方法,完成具體產品的創建。
  • 抽象產品(Product):定義了產品的規範,描述了產品的主要特性和功能。
  • 具體產品(Concrete Product):實現了抽象產品角色所定義的接口,由具體工廠來創建,它同具體工廠之間一一對應。
類圖分析:

核心代碼:
  1. 圖形的抽象類
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();

}
  1. 圖形的具體實現類(這裏僅列舉小萬、小李繪製圓形的實現,重在這種設計思想的領悟)
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("-------------------");
    }
}
  1. 將繪製圖形的實例化功能抽象爲抽象方法,在不同的繪製者的子類中具體實現。
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 "";
        }
    }
}

  1. 小萬這個繪製者的具體實現類。
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;
    }
}

  1. 小李這個繪製者的具體實現類。
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;
    }
}
總結:

工廠方法模式非常符合“開閉原則”,當需要增加一個新的產品時,我們只需要增加一個具體的產品類和與之對應的具體工廠即可,無須修改原有系統。同時在工廠方法模式中用戶只需要知道生產產品的具體工廠即可,無須關係產品的創建過程,甚至連具體的產品類名稱都不需要知道。

雖然他很好的符合了“開閉原則”,但是由於每新增一個新產品時就需要增加兩個類,這樣勢必會導致系統的複雜度增加。

工廠方法模式就講解到這裏,後面我們將會引入另一種設計模式——抽象工廠模式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章