簡單工廠模式中我們介紹了簡單工廠模式,提到了簡單工廠模式違背了開閉原則,而“工廠方法模式”是對簡單工廠模式的進一步抽象化,其好處是可以使系統在不修改原來代碼的情況下引進新的產品,即滿足開閉原則。
優點:
- 用戶只需要知道具體工廠的名稱就可得到所要的產品,無須知道產品的具體創建過程。
- 靈活性增強,對於新產品的創建,只需多寫一個相應的工廠類。
- 典型的解耦框架。高層模塊只需要知道產品的抽象類,無須關心其他實現類,滿足迪米特法則、依賴倒置原則和里氏替換原則。
缺點:
- 類的個數容易過多,增加複雜度
- 增加了系統的抽象性和理解難度
- 抽象產品只能生產一種產品,此弊端可使用抽象工廠模式解決。
應用場景:
- 客戶只知道創建產品的工廠名,而不知道具體的產品名。如 TCL 電視工廠、海信電視工廠等。
- 創建對象的任務由多個具體子工廠中的某一個完成,而抽象工廠只提供創建產品的接口。
- 客戶不關心創建產品的細節,只關心產品的品牌
結構
- 工廠接口:提供了創建產品的接口,調用者通過它訪問具體工廠的工廠方法 createProduct() 來創建產品。
- 具體工廠:主要是實現抽象工廠中的抽象方法,完成具體產品的創建。
- 產品接口:定義了產品的規範,描述了產品的主要特性和功能。
- 具體產品:實現了抽象產品角色所定義的接口,由具體工廠來創建,它同具體工廠之間一一對應。
UML關係圖:
代碼實現
文件結構:
工廠接口:
package factory;
/**************************************************************************************************
@Copyright 2003-2022
@package factory
@date 2022/2/4 21:02
@author qiao wei
@version 1.0
@brief
@history
*************************************************************************************************/
public interface AnimalFarm {
Animal createAnimal();
}
具體工廠:主要是實現抽象工廠中的抽象方法,完成具體產品的創建。
package factory;
/**************************************************************************************************
@Copyright 2003-2022
@package factory
@date 2022/2/4 21:03
@author qiao wei
@version 1.0
@brief
@history
*************************************************************************************************/
public class CattleFarm implements AnimalFarm {
@Override
public Animal createAnimal() {
System.out.println("新牛出生!");
return new Cattle();
}
}
package factory;
/**************************************************************************************************
@Copyright 2003-2022
@package factory
@date 2022/2/4 21:02
@author qiao wei
@version 1.0
@brief
@history
*************************************************************************************************/
public class HorseFarm implements AnimalFarm {
@Override
public Animal createAnimal() {
System.out.println("新馬出生!");
return new Horse();
}
}
產品接口:
package factory;
/**************************************************************************************************
@Copyright 2003-2022
@package factory
@date 2022/2/4 20:59
@author qiao wei
@version 1.0
@brief
@history
*************************************************************************************************/
public interface Animal {
void show();
}
具體產品
package factory;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
/**************************************************************************************************
@Copyright 2003-2022
@package factory
@date 2022/2/4 21:01
@author qiao wei
@version 1.0
@brief
@history
*************************************************************************************************/
public class Cattle implements Animal {
JScrollPane sp;
JFrame jf = new JFrame("工廠方法模式測試");
public Cattle() {
Container contentPane = jf.getContentPane();
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1, 1));
p1.setBorder(BorderFactory.createTitledBorder("動物:牛"));
sp = new JScrollPane(p1);
contentPane.add(sp, BorderLayout.CENTER);
JLabel l1 = new JLabel(new ImageIcon("src/factory/res/A_Cattle.jpg"));
p1.add(l1);
jf.pack();
jf.setVisible(false);
//用戶點擊窗口關閉
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void show() {
jf.setVisible(true);
}
}
package factory;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
/**************************************************************************************************
@Copyright 2003-2022
@package factory
@date 2022/2/4 21:00
@author qiao wei
@version 1.0
@brief
@history
*************************************************************************************************/
public class Horse implements Animal {
JScrollPane sp;
JFrame jf = new JFrame("工廠方法模式測試");
public Horse() {
Container contentPane = jf.getContentPane();
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1, 1));
p1.setBorder(BorderFactory.createTitledBorder("動物:馬"));
sp = new JScrollPane(p1);
contentPane.add(sp, BorderLayout.CENTER);
JLabel l1 = new JLabel(new ImageIcon("src/factory/res/A_Horse.jpg"));
p1.add(l1);
jf.pack();
jf.setVisible(false);
//用戶點擊窗口關閉
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void show() {
jf.setVisible(true);
}
}
配置類:
package factory;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
/**************************************************************************************************
@Copyright 2003-2022
@package factory
@date 2022/2/4 21:11
@author qiao wei
@version 1.0
@brief
@history
*************************************************************************************************/
public class ReadXML2 {
public static Object getObject() {
try {
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src/factory/res/config2.xml"));
NodeList nl = doc.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String cName = "factory." + classNode.getNodeValue();
System.out.println("新類名:" + cName);
Class<?> c = Class.forName(cName);
Object obj = c.newInstance();
return obj;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
資源文件:
xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>CattleFarm</className>
</config>
運行結果:
結論:
工廠方法模式和簡單工廠模式在定義上的不同是很明顯的。工廠方法模式的核心是一個抽象工廠類,而不像簡單工廠模式, 把核心放在一個實類上。工廠方法模式可以允許很多實的工廠類從抽象工廠類繼承下來, 從而可以在實際上成爲多個簡單工廠模式的綜合,從而推廣了簡單工廠模式。
工廠方法相比於簡單工廠模式的優點是增加一個產品,只需要增加一個具體工廠類和具體產品類,沒有修改原先的工廠類,符合開閉原則。缺點是客戶端的代碼會需要修改(簡單工廠模式的客戶端不需要修改),隨着產品的繼續增加,所要實現的類的個數也會隨之增大。