Spring学习笔记01 - Spring 工厂设计模式-反射解藕

—笔记总结来自孙哥说Spring5

引言

EJB(Enterprise Java Bean)是重量级的框架,存在问题:

  • 运行环境苛刻
  • 代码移植性差
    所以称EJB是重量级框架。

什么是Spring?

Spring 是一个轻量级的框架.

  • 它整合了多种设计模式,使开发环境更方便。
  • 对运行环境没有额外要求
    开源, Tomcat resion jetty
    收费, weblogic websphere
  • 代码移植性高
    不需要实现额外接口

Spring 开发

它可以涉及解决Java开发的每一层问题,而struts2, mybatis 只解决某一层问题。
Spring学习笔记01 - Spring 工厂设计模式-反射解藕_第1张图片
整合设计模式

  • 工厂
  • 代理
  • 模版
  • 策略

设计模式

  • 广义定义:面向对象设计中,解决特定问题的经典代码。
  • 狭义定义:GOF4人帮定义的23种设计模式。
    (工厂、适配器、装饰器、门面、代理、模版…)

工厂设计模式

什么是工厂设计模式?

概念:通过工厂类创建对象。

//我们传统使用new创建对象形式:
	User user = new User();
	UserDAO userDAO = new UserDAO();

好处:解藕。
藕合: 是指代码块间强关联关系,一个地方改变,其他很多地方需要跟着改变,不利于代码间的维护

出现耦合如下,新建一个接口,需要对相关代码进行修改,此时就比较麻烦,尤其是对大工程。

package com.gogogo;

public class Test {
    public static void main(String[] args) {
        //UserService userService = new UserServiceImplnew(); 
        UserService userService = new UserServiceImpl();
        userService.login("asds", "asds");
        User user = new User("asds", "123456");
        userService.register(user);
    }
}

创建工厂类进行解藕

创建BeanFactory.java 文件

package com.gogogo;

public class BeanFactory {
    public static UserService getUserService(){
        return new UserServiceImpl();
    }
}

在test文件中通过BeanFactory.getUserService()得到UserService对象,此时就在test文件中解藕了。

package com.gogogo;

public class Test {
    public static void main(String[] args) {
        //UserService userService = new UserServiceImplnew();
        //UserService userService = new UserServiceImpl();
        UserService userService = BeanFactory.getUserService();
        userService.login("asds", "asds");
        User user = new User("asds", "123456");
        userService.register(user);
    }
}

但是,我们在BeanFactory里又引入了藕合,因为是new 的对象。
怎么解决呢?
我们知道 对象的创建方式有两种方式:

  • 直接调用构造方法,创建对象。
UserService userService = new UserServiceImpl();
  • 通过反射的形式,创建对象,解耦合
Class clazz = Class.forName("com.gogogo.UserServiceImpl");
UserService userService =(UserService) clazz.newInstance();

所以, 解决方法如下:

package com.gogogo;

public class BeanFactory {
    public static UserService getUserService(){
//        return new UserServiceImpl();
        UserService userService = null;
        try {
            Class clazz = Class.forName("com.gogogo.UserServiceImpl");
            userService =(UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return userService;
    }
}

反射加配置文件解藕

只通过反射,实现完全解决藕合 有点难,字符串还是需要再次改,此时不能通过一次反射解决问题,我们可以通过配置properties文件 对这个字符串进行解藕,如下:

Class clazz = Class.forName("com.gogogo.UserServiceImpl");

在resources文件夹下创建applicationContext.properties.java配置文件,名字可以自取。

#properties集合来存储 properties文件内容
#是特殊的Map, key = String value = String
#properties[userService] = com.gogogo.UserServiceImpl
#Properties.getProperty("userService)
userService = com.gogogo.UserServiceImpl

BeanFactory.java 文件修改如下:

package com.gogogo;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class BeanFactory {
    private static Properties env = new Properties(); //创建properties集合
    //IO在Java操作当中是一个系统级资源,一般尽量避免重复性打开,最好在程序启动的时候一次性打开读取内容
    //使用静态代码块读取内容
    static{ 
        //第一步,获取IO流
        InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
        //第二步,文件中封装Properties集合中key=userService value=com.gogogo.UserServiceImpl
        try {
            env.load(inputStream);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static UserService getUserService(){
//        return new UserServiceImpl(); //藕合
        UserService userService = null;
        try {
            //Class clazz = Class.forName("com.gogogo.UserServiceImpl"); //此处的字符串也是有耦合的
            Class clazz = Class.forName(env.getProperty("userService"));
            userService =(UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return userService;
    }
}

此时,工厂类里就没有藕合了,通过反射和配置文件一起实现了解藕。

若有一天不满意 UserServiceImpl 这个实现类 ,想用一个更好的实现方式,那么就不需要改变现有代码,只新增实现类文件UserServiceImplNewOne,让它取实现UserService 接口,实现接口里面的内容,然后在配置文件里修改下配置类名即可。

配置简单的工厂类实例过程

1. 在BeanFactory.java里定义方法,主要是4步。

public static UserDAO getUserDAO(){
        UserDAO userDAO = null; //1.创建对象
        Class clazz = null;
        try {
            clazz = Class.forName(env.getProperty("userDAO"));//2.反射获取类
            userDAO=(UserDAO) clazz.newInstance();//3.实例化赋值
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return userDAO; //4.返回对象
    }

2. 在properties里配置好路径(包名+类名)

配置文件applicationContext.properties.java

#userService = com.gogogo.UserServiceImpl
userDAO = com.gogogo.UserDAOImpl

3. 创建对象 - 完全解藕

//private UserDAO userDAO = new UserDAOImpl(); //藕合
private UserDAO userDAO = BeanFactory.getUserDAO(); //解藕,配置BeanFactory和properties文件
}

通用工厂

由之前的代码配置,我们可以看出BeanFactory.java 里面由大量重复性代码,所以需要整改代码。

减少代码冗杂,编写通用生产类

Spring学习笔记01 - Spring 工厂设计模式-反射解藕_第2张图片
整改如下

//通用工厂
//key 配置文件中key(即userService, userDAO)
public static Object getBean(String key){
    Object ret = null;
    try{
        Class clazz = Class.forName(env.getProperty(key));
        ret = clazz.newInstance();
    }catch (Exception e){
        e.printStackTrace();
    }
    return ret;
}

BeanFactory.java 完整代码如下。

  • IO读取配置文件
  • 通用工厂设计
public class BeanFactory {
    private static Properties env = new Properties(); //创建properties集合
    //IO在Java操作当中是一个系统级资源,一般尽量避免重复性打开,最好在程序启动的时候一次性打开读取内容
    //使用静态代码块读取内容
    static{
        //第一步,获取IO流
        InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
        //第二步,文件中封装Properties集合中key=userService value=com.gogogo.UserServiceImpl
        try {
            env.load(inputStream);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //通用工厂-解决方案如下
    //key 配置文件中key(即userService, userDAO)
    public static Object getBean(String key){
        Object ret = null;
        try{
            Class clazz = Class.forName(env.getProperty(key));
            ret = clazz.newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return ret;
    }
}

获取 反射创建的对象:

//返回值是Object类,需强转
UserService userService = (UserService) BeanFactory.getBean("userService");       
UserDAO userDAO = (UserDAO) BeanFactory.getBean("userDAO"); 

总结- 通用工厂的使用方式

  1. 定义类型(定义类)
  2. 通过配置文件的配置告知工厂,做相应配置(原来是通过new创建对象,由藕合)key = value
  3. 通过工厂获取类的对象,主要强转类型

总结

Spring核心是工厂设计模式,解藕合。Spring为我们提供的工厂,命名为 ApplicationContext, 配置文件是application.xml。

学习开心❤️
加加油~

你可能感兴趣的:(Java基础类,java,spring)