引言
spring是一个轻量级的javaee解决方案,整合众多优秀设计模式(设计模式是指:面向对象设计中,解决特定问题的经典代码)。spring中最常用的设计模式是工厂设计模式,工厂设计模式解决了创建对象的耦合问题,下面我将带大家了解spring是如何利用工厂模式创建对象的。
工厂模式是什么?
工厂模式是23种设计模式中的一种,思想是通过工厂类创建对象。下面我们模拟一下简单的工厂模式,让大家直观感受一下工厂模式解决了什么问题。首先我们准备一个StudentService接口及其实现类:
//学生服务接口
public interface StudentService {
//登录
public boolean login(String userName,String passWord);
}
//学生服务实现类
public class StudentServiceImpl implements StudentService{
//登录
public boolean login(String userName,String passWord){
System.out.println("login-->userName="+userName+",passWord="+passWord);
return true;
}
}
在初学java时,我们使用一个类时会new一个对象,代码如下:
//测试
public class Test {
public static void main(String[] args) {
//创建对象
StudentService studentService = new StudentServiceImpl();
studentService.login("zhangsan","123");
//输出结果:login-->userName=zhangsan,passWord=123
}
}
而使用工厂模式创建对象时,我们需要创建一个工厂类,再调用工厂类的对应方法创建对象,首先创建工厂类:
//工厂类
public class Factory {
//该方法返回学生服务对象
public static StudentService getStudentService(){
return new StudentServiceImpl();
}
}
工厂模式创建对象:
//测试,工厂类创建对象
public class Test {
public static void main(String[] args) {
//使用工厂类的对应方法创建学生服务对象
StudentService studentService = Factory.getStudentService();
studentService.login("zhangsan","123");
//输出结果:login-->userName=zhangsan,passWord=123
}
}
实际上,工厂模式就是用一个工厂类统一创建对象,通过对比我们发现工厂模式创建对象比传统new对象的方式更复杂了,好像还没啥用,这不多此一举吗?
为什么spring不使用new创建对象?
这就要提到开闭原则 (Open Close Principle):对扩展开放,对修改关闭。假设我们推出了StudentService接口的第二代实现类StudentServiceImpl02,使用new的方式,我们需要修改源码,违背了对修改关闭的原则。上诉工厂模式虽然减少了代码的修改量,但还是需要修改源码。spring的工厂类并不是通过new创建对象的,而是通过反射创建对象,彻底解决了代码耦合的情况。
(不了解反射的朋友可以通过这篇博客了解反射机制https://blog.csdn.net/qq_45874107/article/details/114498777)。
spring中的反射工厂
下面我们看看spring是如何通过反射解决代码耦合问题的。首先我们采用反射机制改变上诉例子的工厂代码
//通过反射机制创建对象的工厂类
public class Factory {
//该方法返回学生服务对象
public static StudentService getStudentService(){
StudentService studentService = null;
try {
//获取StudentServiceImpl类
Class studentServiceclass = Class.forName("StudentServiceImpl");
//通过反射创建对象
studentService = (StudentService) studentServiceclass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return studentService;
}
}
细心的网友会发现还是需要修改传入Class.forName()中的字符串才能创建我们新推出的第二代实现类。spring采用配置文件的形式传入参数,我们这里用properties配置文件模拟spring的配置文件传参,下面我们介绍一下properties。
properties是以键值对的方式存储数据的,继承结构图如下:
它的特点是key和value都只能是字符串。
说回spring的反射工厂,有了配置文件之后,我们就不需要Class.forName()中写死某一字符串了,而是通过key读取配置文件中的value,首先创建一个properties配置文件,内容如下:
将上诉工厂类写死的字符串改为通过key读取到的value,加上properties文件读取的代码后,工厂类变成:
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
//通过反射机制创建对象的工厂类
public class Factory {
//创建一个properties
public static Properties properties = new Properties();
//静态代码块,类加载时期将配置文件内容封装到properties中
static{
//获取I/O流
InputStream inputStream = Factory.class.getResourceAsStream("student.properties");
//文件内容封装到properties中
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
//关闭流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//该方法返回学生服务对象
public static StudentService getStudentService(){
StudentService studentService = null;
try {
//获取StudentServiceImpl类
Class studentServiceclass = Class.forName(properties.getProperty("studentService"));
//通过反射创建对象
studentService = (StudentService) studentServiceclass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return studentService;
}
}
测试结果:
//测试,工厂类创建对象
public class Test {
public static void main(String[] args) {
//使用工厂类的对应方法创建学生服务对象
StudentService studentService = Factory.getStudentService();
studentService.login("zhangsan","123");
//输出结果:login-->userName=zhangsan,passWord=123
}
}
这样我们就实现了改变配置文件内容就能创建我们新推出的第二代实现类,同时不修改源码。
总结
我们讲述了spring中最常用工厂设计模式的原理和为什么使用工厂设计模式,同时以简化的代码重现了spring框架是如何创建对象的,希望对大家有所帮助。