Java设计模式-创建型设计模式-工厂方法模式(工厂模式)
从这一专栏开始将学习设计模式,上课学习和自己总结归纳的笔记将总结出来供大家参考。
参考书籍:《设计模式就该这样学》
其他文章:
文章目录
一、创建型设计模式
创建型模式对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离,对客户端代码需要调用对象的时候隐藏了类的实例化的创建细节。
其中包括:简单工厂模式(不在GoF23种设计模式中)、工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式。
二、工厂方法模式(也称为工厂模式)
1.工厂方法模式定义
工厂方法模式: 不再提供一个工厂类来统一负责所有产品的创建,而是将具体产品的创建过程交给专门的工厂子类去完成。
如果出现新的类型,只需要为这种新类型定义一个具体的工厂类就可以创建新产品的实例。定义一个用于创建对象的接口,但让子类决定将哪一个类实例化,让一个类的创建延迟到子类。
在GoF23种设计模式中属于创建型设计模式:
其中包括:简单工厂模式(不在GoF23种设计模式中)、工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式。
2.工厂方法模式的角色
抽象产品:定义产品的接口,是工厂方法模式所创建对象的公共父类
具体产品:实现了抽象产品的接口,某类型的具体产品由专门的工厂创建
抽象工厂:它声明了工厂方法,用于返回一个产品。工厂方法模式的核心,所有创建对象的工厂必须实现该接口
具体工厂:抽象工厂类的子类,实现了抽象工厂中声明的工厂方法,返回一个具体产品类的实例
3.工厂方法模式的特点
优点:
1.用户只需要关心产品对应的工厂,甚至无需关心创建细节或具体产品类的类名
2.基于工厂角色和产品的多态性设计是工厂模式的关键。它能自主决定如何创建哪种产品对象,而创建细节都封装在具体工厂内部
3.在系统要添加新的产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,只要添加一个具体工厂和具体产品即可,从而提高系统的可扩展性(符合开闭原则)
缺点:
1.在添加新产品时,要编写新的具体产品类,并要提供与之对应的具体工厂类。系统软件个数也成对增加,从而增加了系统的复杂度,带来更多开销
2.由于系统的可扩展性,在客户端中要引入抽象层进行定义,从而增加了系统的抽象性和理解难
4.工厂方法模式的类图
5.工厂方法模式的代码实现
案例:
抽象产品:日志记录器
产品:文件日志记录器、数据库日志记录器
抽象工厂:日志工厂
具体工厂:文件日志记录器工厂、数据库日志记录器工厂
类图如下:
具体代码实现:
v1.0版本
抽象产品(日志记录器)接口和产品类(文件日志记录器、数据库日志记录器)
/**
* @author 抽象日志产品类
* @create 2022-03-29 14:32
*/
public interface Logger {
void writeLog();
}
/**
* 数据库日志记录器类
* @author WxrStart
* @create 2022-03-29 14:34
*/
public class DatabaseLogger implements Logger {
@Override
public void writeLog() {
System.out.println("数据库日志记录器执行了");
}
}
/**
* 文件日志记录器类
* @author WxrStart
* @create 2022-03-29 14:33
*/
public class FileLogger implements Logger{
@Override
public void writeLog() {
System.out.println("文件日志记录器执行了");
}
}
抽象工厂接口(日志工厂)和具体工程类(文件日志记录器工厂、数据库日志记录器工厂)
/**
* 抽象日志工厂类
* @author WxrStart
* @create 2022-03-29 14:13
*/
public interface Factory {
Logger createLogger();
}
/**
* 文件日志记录器工厂类
* @author WxrStart
* @create 2022-03-29 14:35
*/
public class FileLoggerFactory implements Factory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
/**
* 数据库日志记录器工厂类
* @author WxrStart
* @create 2022-03-29 14:35
*/
public class DatabaseLoggerFactory implements Factory{
@Override
public Logger createLogger() {
return new DatabaseLogger();
}
}
客户端类和结果
public class Test {
public static void main(String[] args) {
Factory loggerFactory1=new FileLoggerFactory();
Factory loggerFactory2=new DatabaseLoggerFactory();
loggerFactory1.createLogger().writeLog();
loggerFactory2.createLogger().writeLog();
}
}
v2.0版本
上述的类都不变,通过properties文件和反射动态地创建类
ConfigUtils
public class ConfigUtils {
/**
* 从properties文件中创建Bean对象
* @param fileName properties文件名
* @param key包含的Bean对象的类名的配置项
* @return Bean实例
*/
public static <T>T getBeanFromProp(String fileName,String key) {
try {
Properties pros = new Properties();
InputStream is = ConfigUtils.class.getClassLoader().getResourceAsStream(fileName);
//加载配置文件
pros.load(is);
//通过反射创建Bean实例
Class clazz = Class.forName(pros.getProperty(key));
T bean=(T)clazz.newInstance();
return bean;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Factory.properties
FactoryClassName=com.designpatter.factorymetho.factory.FileLoggerFactory
客户端类和结果
public class Test {
public static void main(String[] args) {
Factory loggerFactory3 = ConfigUtils.getBeanFromProp("Factory.properties", "FactoryClassName");
loggerFactory3.createLogger().writeLog();
}
}