Spring5深入浅出篇:Spring工厂设计模式拓展应用

简单工厂实现

这里直接上代码举例子

UserService.java

public interface UserService {
    public void register(User user);

    public void login(String name, String password);
}

UserServiceImpl.java

public class UserServiceImpl implements UserService {
    private UserDAO userDAO = new UserDAOImpl();

    public UserDAO getUserDAO() {
        return userDAO;
    }

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    @Override
    public void register(User user) {
        userDAO.save(user);
    }

    @Override
    public void login(String name, String password) {
        userDAO.queryUserByNameAndPassword(name, password);
    }
}

UserDAOImpl.java

public class UserDAOImpl implements UserDAO {
    @Override
    public void save(User user) {
        System.out.println("insert into user = " + user);
    }

    @Override
    public void queryUserByNameAndPassword(String name, String password) {
        System.out.println("query User name = " + name+" password = "+password);
    }
}

为了方便测试更直观看到结果UserDAOImpl的方法采用打印一条字符串来体现,下面就通过测试类来调用UserService

测试类

/**
     *  用于测试:工厂类进行解耦合的操作
     */
    @Test
    public void test1() {
       UserService userService = new UserServiceImpl();


        UserService userService = (UserService) BeanFactory.getBean("userService");

        userService.login("name", "suns");


        User user = new User("suns", "123456");
        userService.register(user);


    }

最终结果如下:

spring中如何使用工厂模式_User

spring中如何使用工厂模式_spring_02

可以发现当我们在上图中就出现了耦合,当我们需要重新换一个实现类的时候需要重新修改代码在进行编译部署.下面就通过工厂设计模式来解决这个问题.

创建工厂类

BeanFactory.java

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

这样就通过了工厂类中提供的getUserService方法来获取对象,这样测试类中就彻底没有耦合了,但是new对象的方法写到了工厂类中,下面来看看如何解决.

对象的创建方式

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

重新修改工厂类

BeanFactory.java

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

        return userService;
    }
}

通过反射并不能完全解决耦合的问题,因为这里的全限定类名字符串如果需要修改,也涉及到需要修改源码.这里我们通过读取resources下的properties文件来进行优化

applicationContext.properties

userService = com.baizhiedu.basic.UserServiceImpl

BeanFactory.java

private static Properties env = new Properties();

    static{
        try {
            //第一步 获得IO输入流
            InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
            //第二步 文件内容 封装 Properties集合中 key = userService value = com.baizhixx.UserServiceImpl
            env.load(inputStream);

            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

public static UserService getUserService() {

        UserService userService = null;
        try {
                                         //com.baizhiedu.basic.UserServiceImpl
            Class clazz = Class.forName(env.getProperty("userService"));
            userService = (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return userService;

    }

这里就是直接通过配置文件读取对应的全限定类名即可,使我们程序之间的耦合解决.即便是我们还需要解决UserDaoImpl的耦合也是异曲同工,只需要将UserServiceImpl,改成UserDaoImpl

UserDAO解耦

BeanFactory.java

public static UserDAO getUserDAO(){

        UserDAO userDAO = null;
        try {
            Class clazz = Class.forName(env.getProperty("userDAO"));
            userDAO = (UserDAO) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return userDAO;

    }

applicationContext.xml

<bean id="userDAO" class="com.baizhiedu.basic.UserDAOImpl"></bean>

通用工厂实现

spring中如何使用工厂模式_User_03

可以发现上图代码出现冗余,我们应该对这种重复的代码块进行抽取

通用工厂代码

public class BeanFactory{
 
 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;
 }
}

这样只需要在applicationContext.xml中增加对应配置,就可以通过getBean方法传入对应的key从工厂获取到对象了.

@Test
    public void test1() {
        UserService userService = (UserService) BeanFactory.getBean("userService");

        userService.login("name", "suns");


        User user = new User("suns", "123456");
        userService.register(user);


    }

通用工厂的使用方式

1.定义类型(需要创建对象的类)

2.通过配置文件的配置告知工厂(applicationContext.properties)

以key = value的形式

3.通过工厂获得类的对象

Object ret = BeanFactory.getBean("key")

总结

Spring的本质其实就是工厂+配置文件的形式,但是Spring提供的工厂肯定是比我们现在设计的工厂功能要更加强大.