简单工厂模式中我们介绍了简单工厂模式,提到了简单工厂模式违背了开闭原则,而“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
- 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
- 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
应用场景:
- 客户只知道创建产品的工厂名,而不知道具体的产品名。如 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>
运行结果:
结论:
工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。
工厂方法相比于简单工厂模式的优点是增加一个产品,只需要增加一个具体工厂类和具体产品类,没有修改原先的工厂类,符合开闭原则。缺点是客户端的代码会需要修改(简单工厂模式的客户端不需要修改),随着产品的继续增加,所要实现的类的个数也会随之增大。