工廠方法模式屬於建構式模式(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,有二個實作類別XMLLoader
及JSONLoader
為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");
}
}
建構XMLLoader
或JSONLoader
物件時透過各自的工廠類XMLLoaderFactory
及JSONLoaderFactory
來建構,此為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()
等。
沒有留言:
張貼留言