定義一個用於建立對象的接口,讓子類決定實例化哪個類。Factory Method使一個類的實例化延遲到其子類。java
虛構造器(virtual constructor)數據庫
框架使用抽象類定義和維護對象之間的關係。這些對象關係的建立也一般由框架負責。網絡
考慮一個向用戶顯示多個文檔的應用框架。在這個框架中,兩個主要的抽象類Application和Document。客戶經過重定義其子類實現具體應用。例如,定義一個繪圖應用,定義類DrawingApplication和DrawingDocument。Application類負責管理Document類並根據需求建立它們——例如,當用戶從菜單選擇Open或New的時候。框架
由於被實例化的特定Document子類是與特定應用相關的,因此Application類不可能預測到哪一個Document子類被實例化。ide
Factory Method模式封裝了哪一個Document子類將被建立的信息並將這些信息從框架中分離出來,以下圖所示。ui
Application 的子類重定義Application的抽象操做CreateDocument已返回適當的Document子類對象。Application子類實例化後,其能夠實例化與文檔相關的類而無須知道這些文檔的類。稱CreateDocument是一個工廠方法,它負責生產一個對象。this
在處理大型資源密集型對象(好比數據庫鏈接、文件系統和網絡資源)時,常常會碰到這種資源需求spa
複用現有對象的方法:3d
1. 建立存儲空間存放全部已建立的對象code
2. 當他人請求一個對象時,程序將在對象池中搜索可用對象
3. 而後將其返回給客戶端代碼
4. 若是沒有可用對象,就建立一個新對象,並添加到對象池中
1) 能夠避免建立者和具體產品之間的緊密耦合
2) 單一職責原則。 能夠將產品建立代碼放在程序的單一位置, 從而使得代碼更容易維護
3) 開閉原則。 無需更改現有客戶端代碼, 你就能夠在程序中引入新的產品類型
buttons/Button.java: 通用產品接口
package factory_method.buttons; /** * @author GaoMing * @date 2021/7/18 - 11:43 * Common interface for all buttons. */ public interface Button { void render(); void onClick(); }
buttons/HtmlButton.java: 具體產品
package factory_method.buttons; /** * @author GaoMing * @date 2021/7/18 - 11:43 * HTML button implementation. */ public class HtmlButton implements Button{ public void render() { System.out.println("<button>Test Button</button>"); onClick(); } public void onClick() { System.out.println("Click! Button says - 'Hello World!'"); } }
buttons/WindowsButton.java: 另外一個具體產品
package factory_method.buttons; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * @author GaoMing * @date 2021/7/18 - 11:45 * Windows button implementation. */ public class WindowsButton implements Button{ JPanel panel = new JPanel(); JFrame frame = new JFrame(); JButton button; public void render(){ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel("Hello World!"); label.setOpaque(true); label.setBackground(new Color(235,233,126)); label.setFont(new Font("Dialog", Font.BOLD, 44)); label.setHorizontalAlignment(SwingConstants.CENTER); panel.setLayout(new FlowLayout(FlowLayout.CENTER)); frame.getContentPane().add(panel); panel.add(label); onClick(); panel.add(button); frame.setSize(320, 200); frame.setVisible(true); onClick(); } public void onClick() { button = new JButton("Exit"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame.setVisible(false); System.exit(0); } }); } }
factories/Dialog.java: 基礎建立者
package factory_method.factories; import factory_method.buttons.Button; /** * @author GaoMing * @date 2021/7/18 - 11:50 * Base factory class. Note that "factory" is merely a role for the class. It * should have some core business logic which needs different products to be * created. */ public abstract class Dialog { public void renderWindow() { // ... other code ... Button okButton = createButton(); okButton.render(); } /** * Subclasses will override this method in order to create specific button * objects. */ public abstract Button createButton(); }
factories/HtmlDialog.java: 具體建立者
package factory_method.factories; import factory_method.buttons.HtmlButton; import factory_method.buttons.Button; /** * @author GaoMing * @date 2021/7/18 - 11:54 */ public class HtmlDialog extends Dialog{ @Override public Button createButton() { return new HtmlButton(); } }
factories/WindowsDialog.java: 另外一個具體建立者
package factory_method.factories; import factory_method.buttons.WindowsButton; import factory_method.buttons.Button; /** * @author GaoMing * @date 2021/7/18 - 11:54 */ public class WindowsDialog extends Dialog{ @Override public Button createButton() { return new WindowsButton(); } }
Demo.java: 客戶端代碼
package factory_method; import factory_method.factories.HtmlDialog; import factory_method.factories.WindowsDialog; import factory_method.factories.Dialog; /** * @author GaoMing * @date 2021/7/18 - 11:56 * Demo class. Everything comes together here. */ public class Demo { private static Dialog dialog; public static void main(String[] args) { configure(); runBusinessLogic(); } /** * The concrete factory is usually chosen depending on configuration or * environment options. */ static void configure() { if (System.getProperty("os.name").equals("Windows 10")) { dialog = new WindowsDialog(); } else { dialog = new HtmlDialog(); } } /** * All of the client code should work with factories and products through * abstract interfaces. This way it does not care which factory it works * with and what kind of product it returns. */ static void runBusinessLogic() { dialog.renderWindow(); } }
OutputDemo.png: 執行結果 (WindowsDialog)