定义一个用于建立对象的接口,让子类决定实例化哪个类。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)