反射工厂设计模式
顶级父类接口
public interface IBaseDao {
void add();
}
顶级父类接口的实现类
public class StudentDaoImpl implements IBaseDao {
public StudentDaoImpl() {
System.out.println("StudentDaoImpl......");
}
@Override
public void add() {
System.out.println("Student...add...");
}
}
配置文件-供反射使用-根据key取value(全限定名)
StudentDaoImpl = stu.aistar.design.factory.reflect.StudentDaoImpl2
利用枚举特性写一个工具类-用来读取配置文件里面的value(全限定名)
public enum PropUtil {
INSTANCE;
// 定义一个Properties属性
private Properties properties;
PropUtil(){
//可以在构造方法 - 初始化的
//Properties对象就是.properties属性文件[encoding=utf-8]在内存中的映射.
properties = new Properties();
//固定的语法 - 死记住
//获取属性文件字节输入流
InputStream in = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("stu/aistar/design/factory/reflect/bean.properties");
try {
//Properties对象就是.properties属性文件[encoding=utf-8]在内存中的映射.
properties.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//普通方法
public String getValue(String key){
//确认properties不为null
return properties == null ? null : properties.getProperty(key);
}
}
创建反射工厂模式-利用刚读取到的全限定名-利用反射技术创建接口的实现类对象-从而对接口的方法进行操作
/**
* 本类用于演示:反射工厂 - 反射工厂既能够保证在新增一个产品的时候,能够遵守"开闭原则",
* 又能够保证始终仅仅只有一个工厂类.
*
* Properties + 反射 + 泛型方法/泛型类
*/
public class BaseFactory<T> {
//面向接口编程
//泛型方法 - 静态方法<T>,同时也要设置泛型类
public T getInstance(String type){
T t = null;
//传进来的type是一个全限定类型,我们需要用forName方法
try {
//获取class实例的方式
Class<?> c = Class.forName(type);
//反射调用空参构造
try {
t = (T) c.newInstance(); //构造空参 可以调用接口实现类中的方法
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return t;
}
}
单元测试
public class FactoryTest {
public static void main(String[] args) {
//1. 获取StudentDaoImpl对象
//有多少个产品实现类 - 都是需要配置到bean.properties文件中的.
String stuClass = PropUtil.INSTANCE.getValue("StudentDaoImpl"); //获取的是全限定类型
BaseFactory<StudentDaoImpl> baseFactory = new BaseFactory<>();
// IBaseDao stuDao = baseFactory.getInstance(stuClass);
//
// stuDao.add();
//思考好处
/**
* 场景:如果哪天实现类功能升级了.
* 当一个类的功能拓展之后,尽量不要去动原来的类 - “开闭原则”
* 解决方案一:不推荐,再去写一个类StudentDaoImpl2.java extends StudentDaoImpl.java
* 继承虽然解决了功能的拓展,同时也增加了类之间的耦合性 - “高内聚,低耦合”
*
* 解决方案二:引导如果想要对一个类进行功能的拓展,使用设计原则 - 合成复用原则来替代继承的写法.
*
* 设计原则 - 依赖倒置原则 - 由维护具体-维护抽象.
*
* 凡是代码中用到StudentDaoImpl,代码需要大量的改动
* 代码改动 - 小牧编译 - 重新部署
* IBaseDao stuDao = new StudentDaoImpl();
*
* 只需要修改配置文件即可
* STUDENT_DAO=tech.aistar.design.factory.reflect.StudentDaoImpl2
*/
IBaseDao stuDao = baseFactory.getInstance(stuClass);
stuDao.add();
}
}