工厂方法模式
概念
是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。
角色
- 抽象产品
工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。- 具体产品
这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。- 抽象工厂
是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。- 具体工厂
这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象
UML图如下
简单工厂模式的优缺点
优点
- 用工厂创建客户所需产品,向客户隐藏了具体是哪个产品被实例化,客户只需关心哪个工厂创建那个产品而不需要关心创建细节
- 让工厂自主确定创建何种产品,如何创建完全封装在具体工厂内部
- 符合开闭原则,向系统中添加新产品只需要添加具体的工厂和产品即可
缺点
- 添加新产品需要编写具体产品类以及与之对应的工厂类,类的个数成对增加
适合环境
- 客户端不需要知道他所需要对象的类
- 对于某个产品,客户端清楚地知道应该使用哪个具体工厂服务
例子
现需要一个日志记录器可以通过多种方式来保存日志,例如文件系统和数据库系统,用户只需通过修改配置文件就可以灵活的切换日志方式,并且在设计日志记录器时,开发人员系统对日志记录器做一系列初始化工作,并且初始化参数设置极为复杂。
分析
我们先将实体与简单工厂的角色一一对应
- 抽象产品: Logger
- 具体产品: DatabaseLogger,FileLogger
- 抽象工厂: LoggerFactory
- 具体工厂: DatabaseLoggerFactory,FileLoggerFactory
看不懂不要紧,我们先看UML图,在看代码应该就能理解了
编码
Logger.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:02 PM 2019/7/25
* @Description: 日志记录器接口,充当抽象产品角色
*/
public interface Logger {
public void writeLog();
}
FileLogger.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:06 PM 2019/7/25
* @Description: 文件日志记录器,充当具体的产品角色
*/
public class FileLogger implements Logger {
@Override
public void writeLog() {
System.out.println("文件日志记录");
}
}
DatabaseLogger.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:04 PM 2019/7/25
* @Description: 数据库日志记录器,充当具体产品角色
*/
public class DatabaseLogger implements Logger {
@Override
public void writeLog() {
System.out.println("数据库日志记录");
}
}
LoggerFactory.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:07 PM 2019/7/25
* @Description: 日志记录器工厂接口,充当抽象工厂角色
*/
public interface LoggerFactory {
/**
* 抽象工厂方法
*
* @return
*/
public Logger createLogger();
}
FileLoggerFactory.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:11 PM 2019/7/25
* @Description: 文件日志记录器工厂类,充当具体工厂角色
*/
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
//创建文件日志记录器对象
Logger logger = new FileLogger();
//创建文件,代码略
return logger;
}
}
DatabaseLoggerFactory.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:09 PM 2019/7/25
* @Description: 数据库日志记录器工厂类,充当具体工厂角色
*/
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
//连接数据库,代码略
//创建数据库日志记录器对象
Logger logger = new DatabaseLogger();
//初始化数据库日志记录器,代码略
return logger;
}
}
config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<className>cn.kevinlu98.factorymethod.DatabaseLoggerFactory</className>
</config>
XMLUtil.xml
package cn.kevinlu98.factorymethod;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
/**
* @Author: Kevin·Lu
* @Date: 9:17 PM 2019/7/25
* @Description: 读取xml文件中的字符串参数
*/
public class XMLUtil {
public static Object getBean() {
try {
//创建dom文档对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File("src/cn/kevinlu98/factorymethod/config.xml"));
//获取包含类名的文本节点
NodeList nl = document.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String name = classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c = Class.forName(name);
Object object = c.newInstance();
return object;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Client.java
package cn.kevinlu98.factorymethod;
/**
* @Author: Kevin·Lu
* @Date: 9:12 PM 2019/7/25
* @Description: 工厂方法设计模式 客户端测试
*/
public class Client {
public static void main(String[] args) {
// LoggerFactory factory = (LoggerFactory) XMLUtil.getBean();
LoggerFactory factory = new DatabaseLoggerFactory();
Logger logger = factory.createLogger();
logger.writeLog();
}
}
运行结果
至此,工厂方法设计模式介绍完成,希望能帮助到您