網頁

2020/9/29

Java 設計模式 工廠方法模式 Factory Method Pattern

工廠方法模式屬於建構式模式(Creational Patterns)的一種,目的是用來建構物件。

工廠模式又分為簡單工廠模式(Simple Factory Pattern),工廠方法模式(Factory Method Pattern)及抽象工廠模式(Abstract Factory Pattern)。

在簡單工廠模式中,同介面的子類別物件統一由一個具體工廠類別來建構,但這樣增減新的類別時都要修改到工廠類別中的邏輯,違反開放封閉原則。工廠方法模式進一步把簡單工廠類別中建構物件的方法抽取出來成為工廠類別,負責不同類別的建構,因此有新的類別時,只要同時增加負責建構的工廠類別即可。

工廠方法中主要角色如下:

  • Product:產品介面,定義產品的行為名稱。
  • ConcreteProduct:產品類別,繼承Product,有多種實作,為工廠實際建構的對象。
  • Factory:工廠介面,定義工廠的行為名稱。
  • ConcreteFactory:工廠類別,繼承Factory,負責建構ConcreteProduct。

                       ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┐
                                                                       
                       │                 ┌─────────┐                  │
                   ┌───┼────────────────►│ Factory │                   
                   │                     └─────────┘                  │
                   │   │                      ▲                        
                   │                          │implements             │
                   │   │           ┌──────────┴───────────┐            
                 call              │                      │           │
                   │   │  ┌────────┴─────────┐  ┌─────────┴────────┐   
                   │      │ ConcreteFactory1 │  │ ConcreteFactory2 │  │
                   │   │  └─────┬────────────┘  └─────────────┬────┘   
┌───────────────┐  │            │                             │       │
│               ├──┘   └ ─ ─ ─ ─┼─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┼─ ─ ─ ─┘
│  Client(Main) │               │                             │
│               │◄─┐            │                             │
└───────────────┘  │   ┌ ─ ─ ─ ─┼─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┼─ ─ ─ ─┐
                   │            │                             │       │
                   │   │    create       ┌───────────┐     create      
                   │            │        │  Product  │        │       │
                return │        │        └───────────┘        │        
                   │            │              ▲              │       │
                   │   │        │              │implements    │        
                   │            │   ┌──────────┴──────────┐   │       │
                   │   │        ▼   │                     │   ▼        
                   │       ┌────────┴─────────┐ ┌─────────┴────────┐  │
                   └───┼───┤ ConcreteProduct1 │ │ ConcreteProduct2 │   
                           └──────────────────┘ └──────────────────┘  │
                       │                                               
                       └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘

例如下面Loader介面為Product,有二個實作類別XMLLoaderJSONLoader為ConcreteProduct負責載入不同格式的檔案。

Loader

package com.abc.demo.loader;

public interface Loader {

    void load();
    
}

XMLLoader用來載入xml檔。

XMLLoader

package com.abc.demo.loader;

public class XMLLoader implements Loader {

    XMLLoader() {
        // 複雜的建構邏輯
    }

    @Override
    public void load() {
        System.out.println("Load from XML");
    }

}

JSONLoader用來載入json檔。

JSONLoader

package com.abc.demo.loader;

public class JSONLoader implements Loader {
    
    JSONLoader() {
        // 複雜的建構邏輯
    }

    @Override
    public void load() {
        System.out.println("Load from JSON");
    }

}

建構XMLLoaderJSONLoader物件時透過各自的工廠類XMLLoaderFactoryJSONLoaderFactory來建構,此為ConcreteFactory。工廠類別皆實作LoaderFactory為Factory。

LoaderFactory

package com.abc.demo.loader;

public interface LoaderFactory {

    Loader createLoader();

}

XMLLoaderFactory負責建構XMLLoader

XMLLoaderFactory

package com.abc.demo.loader;

public class XMLLoaderFactory implements LoaderFactory {

    public XMLLoaderFactory() {
    }

    @Override
    public Loader createLoader() {
        // 建構XMLLoader()前的一些邏輯
        return new XMLLoader();
    }

}

JSONLoaderFactory負責建構JSONLoader

JSONLoaderFactory

package com.abc.demo.loader;

public class JSONLoaderFactory implements LoaderFactory {

    public JSONLoaderFactory() {
    }

    @Override
    public Loader createLoader() {
        // 建構JSONLoader()前的一些邏輯
        return new JSONLoader();

    }

}

在客戶端建立Loader的方式改為透過各自的工廠類別產生。

package com.abc.demo;

import com.abc.demo.loader.JSONLoaderFactory;
import com.abc.demo.loader.Loader;
import com.abc.demo.loader.XMLLoaderFactory;

public class Main {

    public static void main(String[] args) {

        Loader xmlLoader = new XMLLoaderFactory().createLoader();
        xmlLoader.load();

        Loader jsonLoader = new JSONLoaderFactory().createLoader();
        jsonLoader.load();

    }

}

若日後有新的Loader,例如YAMLLoader,只要新增對應的工廠類YAMLLoaderFactory並實作LoaderFactory即可。


在Java JDK程式碼中有用到工廠方法模式的例子有Calendar.getInstance()NumberFormat.getInstance()等。


沒有留言:

張貼留言