1. 程式人生 > 其它 >設計模式-工廠方法模式

設計模式-工廠方法模式

技術標籤:設計模式設計模式java

概念

定義一個建立物件的介面,但讓實現這個介面的類來決定例項化哪個類,工廠方法讓類的例項化推遲到子類中進行.工廠方法模式又簡稱為工廠模式(Factory Pattern),又可稱作虛擬構造器模式(Virtual Constructor Pattern)或多型工廠模式(Polymorphic Factory Pattern)

應用場景

由於簡單工廠只提供一個工廠類來進行物件的建立,導致其職責過重,且程式碼不易維護,當系統需要擴充套件時,需要修改原有程式碼,導致違反了開閉原則,故引出工廠方法模式。如下情況可以考慮使用工廠方法模式

  • 客戶端不知道它所需要的物件的類。在工廠方法模式中,客戶端不需要知道具體類名,只需要知道對應的工廠即可,具體的產品由具體工廠物件進行建立,可以將具體工廠類的類名儲存在配置檔案或者資料中,進行動態建立

具體應用

工廠方法模式就是利用了面向物件的多型性,提供抽象工廠型別,讓其實現類(具體工廠類)來決定要建立的具體物件

該模式主要包含如下角色:

  • Factory(抽象工廠):在抽象工廠類中,聲明瞭一個建立方法,用於返回一個抽象產品
  • ConcreteProduct(具體工廠):是抽象工廠的子類,實現了抽象工廠中定義的工廠方法,並可由客戶端呼叫,返回一個具體產品例項
  • Product(抽象產品):定義產品的介面,是工廠方法所建立物件的公共父類
  • ConcreteProduct(具體產品):實現了抽象產品介面,某種型別由專門的具體工廠進行建立,具體工廠和具體產品之間一一對應

程式碼實踐

還是繪製圖形,我們使用工廠方法模式來進行繪製圖形,並且增加了一個使用案例,即通過讀取配置檔案+反射的機制來實現執行時動態生成不同的物件。

首先定義一個產品抽象類,這裡我們的產品就是圖形Graphical

/**
 * 抽象產品類
 * circular 圓形
 * triangle 三角形
 */
public abstract class Graphical {
    public abstract void draw();
    public abstract void erase();
}

定義我們的具體產品,這裡具體的產品為三角形,和圓形。不支援方形

public class Circular extends Graphical {
    @Override
    public void draw() {
        System.out.println("畫了一個圓形");
    }

    @Override
    public void erase() {
        System.out.println("擦掉了一個圓形");
    }
}
public class Triangle extends Graphical {
    @Override
    public void draw() {
        System.out.println("畫了一個三角形");
    }

    @Override
    public void erase() {
        System.out.println("擦掉了一個三角形");
    }
}

然後定義抽象工廠類GraphicalFactory

public interface GraphicalFactory {
    public Graphical createGraphical();
}

定義具體工廠類,因為我們有2個具體產品(三角形和圓形),所以有2個具體工廠(CircularGraphicalFactory和TriangleGraphicalFactory)

//圓形工廠
public class CircularGraphicalFactory implements GraphicalFactory {
    @Override
    public Graphical createGraphical() {
        return new Circular();
    }
}

//三角形工廠 
public class TriangleGraphicalFactory implements GraphicalFactory {
    @Override
    public Graphical createGraphical() {
        return new Triangle();
    }
}

定義通過配置檔案建立物件的工具類ConfigUtil

public class ConfigUtil {

    public static Object getBean() {
        try {
            InputStream in = Test.class.getClassLoader().getResourceAsStream("Graphical.properties");
            Properties props = new Properties();
            InputStreamReader inputStreamReader = new InputStreamReader(in, "UTF-8");
            props.load(inputStreamReader);

            String cName=props.getProperty("factoryClassName");
            //通過類名生成例項物件並將其返回
            Class c=Class.forName(cName);
            Object obj=c.newInstance();
            return obj;
        }
        catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

配置檔案 Graphical.properties

factoryClassName=com.donkeyx.pattern.factory.factorymethod.TriangleGraphicalFactory

測試類

public class Test {

    public static void main(String[] args) {
        System.out.println("---------------------------------使用預設方式進行建立----------------------------------");
        defaultMethod();
        System.out.println("---------------------------------讀取配置檔案方式進行動態建立----------------------------------");
        readConfigFile();
    }


    /**
     * 使用預設方式進行建立
     */
    public static void defaultMethod(){
        //建立一個圓形
        GraphicalFactory factory;
        factory = new CircularGraphicalFactory();
        Graphical circular = factory.createGraphical();
        circular.draw();
        circular.erase();
        //建立一個三角形
        factory = new TriangleGraphicalFactory();
        Graphical triangle = factory.createGraphical();
        triangle.draw();
        triangle.erase();
    }


    /**
     * 讀取配置檔案方式進行動態建立
     */
    public static void readConfigFile() {
        GraphicalFactory factory;
        factory = (GraphicalFactory)ConfigUtil.getBean();
        Graphical graphical = factory.createGraphical();
        graphical.draw();
        graphical.erase();
    }
}

結果
在這裡插入圖片描述

優點

  • 在新產品加入時,無須修改抽象工廠和抽象產品的介面,無須修改客戶端,也無需修改其他的具體工廠和具體產品,只需要再加入一個具體工廠和具體產品就可以了,符合開閉原則,提高了系統的可擴充套件性

缺點

  • 在新產品加入時,需要再加入一個具體工廠和具體產品,類的個數容易過多,增加了程式碼結構的複雜度
  • 增加了系統的抽象性和理解難度