Spring中的解耦合是如何实现的?

Spring中的解耦合是如何实现的?

  1. 首先我们来准备一个最为简单的项目,采取分层的结构【注】此处的客户端调用通过Junit单元测试来模拟。

    以下就是这一次项目的初始的所有代码:
    【注】初始代码仅仅作为展示,可以直接从问题开始看!
    结构为:在这里插入图片描述

    1. User类
    /**
     * 定义一个实体类
     * @version 1.0.0
     * @date 2020 -08-20
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        /**
         * 用户名
         */
        private String username;
        /**
         * 密码
         */
        private String password;
    }
    
    1. DAO层
    /**
     * 用户类 DAO层
     * @version 1.0.0
     * @date 2020 -08-20
     */
    public interface UserDAO {
        /**
         * 保存【模拟】
         * @param user 用户对象
         */
        void save(User user);
        /**
         * 查询【模拟】
         * @param username 用户名
         * @param password 密码
         */
        void query(String username,String password);
    }
    /*------------------------------------------------------------------------*/
    /**
     * User DAO层实现类
     * @version 1.0.0
     * @date 2020 -08-20
     */
    public class UserDAOImpl implements UserDAO{
        @Override
        public void save(User user) {
            System.out.println("user save method --> user : " + user);
        }
        @Override
        public void query(String username, String password) {
            System.out.println("user query method --> username : " + username
                + " password : " + password);
        }
    }
    
    1. Service层
    /**
     * User 业务层
     * @version 1.0.0
     * @date 2020 -08-20
     */
    public interface UserService {
        /**
         * 保存【模拟】
         * @param user 用户对象
         */
        void save(User user);
        /**
         * 查询【模拟】
         * @param username 用户名
         * @param password 密码
         */
        void query(String username,String password);
    }
    /*------------------------------------------------------------------------*/
    /**
     * User 业务层实现类
     * @version 1.0.0
     * @date 2020 -08-20
     */
    public class UserServiceImpl implements UserService{
        private UserDAO userDAO = new UserDAOImpl();
        @Override
        public void save(User user) {
            userDAO.save(user);
        }
        @Override
        public void query(String username, String password) {
            userDAO.query(username, password);
        }
    }
    
  2. 第一次通过客户端的调用【此处通过Junit模拟】

    @Test
    public void test(){
        UserService userService = new UserServiceImpl();
        User user = new User("demo-1","pwd1");
        userService.save(user);
        userService.query("demo-2","pwd2");
    }
    

    得到的结果肯定是和预期一致的:

    user save method --> user : User(username=demo-1, password=pwd1)
    user query method --> username : demo-2 password : pwd2
    
问题就出现了

在这个Junit测试的方法之中,我们可以看到当我们想要操作User的时候会有一段硬编码存在,当我们想要替换实现类(例如 UserServiceImpl2 )的时候,必须要修改原来的代码。这个是我们所不希望的,于是工厂模式就出来了。

要知道,对于工厂模式来说。它就是用来创建对象的!恰好,我们这里使用到的也是需要去创建对象的。

于是我们可以加一个工厂用来创建UserService接口实现类的对象了!

/**
 * 简单工厂为例
 * @version 1.0.0
 * @date 2020 -08-20
 */
public class BeanFactory {
    public static UserService getUserService(){
        return new UserServiceImpl();
    }
}

自然,我们的客户端就不需要硬编码了:

    @Test
    public void test(){
        /*----------------------change begin-----------------------------*/
        UserService userService = BeanFactory.getUserService();
        /*-----------------------change end------------------------------*/
        User user = new User("demo-1","pwd1");
        userService.save(user);
        userService.query("demo-2","pwd2");
    }

输出自然和上方的输出一样。

PS : 在这里我们实现了客户端的解耦合,当我们替换UserService的实现类的时候,对于客户端调用来说,他们是不需要管的。

耦合依旧存在,仅仅是从客户端转移到了BeanFactory类之中了

于是,我们再次思考,获得对象的方式除了new之外,还可以怎么获得呢???

答案是有的 —— 通过反射!于是,我们再次改造一次我们的代码

public static UserService getUserService(){
    /*----------------------change begin-----------------------------*/
    UserService userService = null;
    try {
        Class c = Class.forName("com.demo.service.UserServiceImpl");
        userService  = (UserService) c.getDeclaredConstructor().newInstance();
    } catch (ClassNotFoundException | NoSuchMethodException 
             | InstantiationException | IllegalAccessException 
             | InvocationTargetException e) {
        e.printStackTrace();
    }
    return userService;
    /*-----------------------change end------------------------------*/
}

输出的结果还是一样的,依旧是我们预期的输出!

再次优化

虽然我们通过反射获得了,但是当我们更换实现类的时候,可以发现还是需要去修改代码。所以,还需要继续想方法。在Spring之中有很多配置文件,我们是不是可以也通过读取配置文件的方式呢???

那我们开始把!来一个bean.properties配置文件

service = com.demo.service.UserServiceImpl

于是,我们给BeanFactory来一个改头换面

public class BeanFactory {
    // 获取配置文件
    private static Properties properties = new Properties();
    // 配置文件内容跟着类加载的时候初始化,并且只需要初始化一次
    static {
        try {
            InputStream inputStream =
                    BeanFactory.class.getResourceAsStream("/bean.properties");
            // 加载进去
            properties.load(inputStream);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static UserService getUserService(){
        UserService userService = null;
        try {
            Class c = Class.forName(properties.getProperty("service"));
            userService  = (UserService) c.getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return userService;
    }
}

输出结果和我们预期的结果肯定还是一样的!!!

再次优化,抽出一个通用的方法

既然这个可以解决UserService接口实现类创建的问题,那么在UserService接口实现类之中new出阿里的UserDAO的实现类肯定也是可以如法炮制的!

public static UserDAO getUserDAO(){
        UserService userService = null;
        try {
            Class c = Class.forName(properties.getProperty("dao"));
            userService  = (UserService) c.getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return userService;
    }

这里,如果今后还有PersonDAO,StudentDAO,PersonService,StudentService等等,就会产生很多冗余的代码。

仔细观察,创建对象的方法之中,仅仅变化的就是属性之中的那个key值而已!

于是,我们可以抽取出来一个通用的方法!

public Object getBean(String key){
    Object object = null;
    try {
        Class c = Class.forName(properties.getProperty(key));
        object = c.getDeclaredConstructor().newInstance();
    } catch (ClassNotFoundException | NoSuchMethodException 
             | InstantiationException | IllegalAccessException 
             | InvocationTargetException e) {
        e.printStackTrace();
    }
    return object;
}
结束

这个getBean方法是不是很熟悉呢!!!!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值