Spring工厂模式解耦浅析

程序的耦合

  • 耦合:程序间的依赖关系

    ​ 包括:1.类之间的依赖 2.方法间的依赖

  • 解耦:降低程序间的依赖关系

  • 实际开发中,应该做到,编译期不依赖,运行时才依赖。

  • 解耦的思路:

    ​ 第一步:使用反射来创建对象,而避免使用new关键字。

    ​ 第二步:通过读取配置文件来获取要创建的对象全限定类名。

耦合示例及利用工厂模式解耦

为了更直观的展示编程中的耦合问题,下面通过一个简单的示例来进行分析和解决。首先创建一个新的maven工程,工程内的各个包和子包如图:
在这里插入图片描述
其中dao包和service包中包含持久层和业务层的代码,各自都拥有一个接口以及一个对应的实现类。ui包中的Client类模拟一个表现层,用于调用业务层。

持久层的IAccountDao 接口中的内容如下:

package com.xmy.dao;

/**
 * 账户的持久层接口
 * @author xmy
 */
public interface IAccountDao {
    /**
     * 模拟保存账户
     */
    void saveAccount();
}

其实现类AccountDaoImpl的代码如下:

package com.xmy.dao.impl;

import com.xmy.dao.IAccountDao;

/**
 * 账户的持久层实现类
 * @author xmy
 */
public class AccountDaoImpl implements IAccountDao {

    public void saveAccount() {
        System.out.println("保存了账户");
    }
}

业务层的IAccountService接口代码如下:

package com.xmy.service;

/**
 * 账户业务层的接口
 * @author xmy
 */
public interface IAccountService {
    /**
     * 模拟保存账户
     */
    void saveAccount();
}

其实现类AccountServiceImpl代码如下:

package com.xmy.service.impl;

import com.xmy.dao.IAccountDao;
import com.xmy.dao.impl.AccountDaoImpl;
import com.xmy.service.IAccountService;

/**
 * 账户的业务层实现类
 * @author xmy
 */
public class AccountServiceImpl implements IAccountService {

	private IAccountDao accountDao= new AccountDaoImpl();
    
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

模拟表现层的ui包下的Client类的代码为:

package com.xmy.ui;

import com.xmy.service.IAccountService;
import com.xmy.service.impl.AccountServiceImpl;

/**
 * 模拟一个表现层,用于调用业务层
 * @author xmy
 */
public class Client {
    public static void main(String[] args) {
        IAccountService as = new AccountServiceImpl();
        as.saveAccount();
    }
}

​ 运行结果如图:

在这里插入图片描述

​ 虽然能够完好的运行,但是在实现类AccountServiceImplClient类中,都使用new关键字直接对应接口子类的实例,如果在上面的程序中将AccountDaoImpl或者AccountServiceImpl移除,会导致其他类中的代码编译错误,此时表现层和业务层,及业务层和持久层之间的依赖程度过高,如果将来替换某一层,很可能会造成其他层无法运行,只能通过修改程序代码保证程序运行,这样依赖就会提高维护成本以及造成不必要的麻烦。而在程序中new对象的方式造成了这种程序之间的依赖程度提升,即提升了程序之间的耦合性。

​ 例如在AccountServiceImpl类中,如果我们移除了AccountDaoImpl类,那么编译器会直接报错。如图所示。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

而为了解决这种情况,我们可以使用工厂模式+配置文件来进行解耦。


创建com.xmy.factory.BeanFactory类,用于创建各个层所需要的的对象。

package com.xmy.factory;

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

/**
 * ---------------------------------------------------------
 * Bean: 可重用组件(计算机英语)
 * JavaBean:使用Java语言编写的可重用组件,例如:service层、dao层等
 * JavaBean:通常分为业务Bean和实体Bean
 * 		业务Bean:处理业务逻辑,service层、dao层
 * 		实体Bean:封装数据,例如,为了封装员工信息而编写的Emp实体类.
 * ---------------------------------------------------------
 * 解除耦合:
 * (1)需要提供配置文件,在配置文件中配置service和dao的实现类
 * 		配置内容为:唯一标识=实现类的全限定类名(key=value结构)
 * (2)通过工厂读取配置文件中配置的全限定类名,利用反射创建对象。
 * 		xml配置文件、properties配置文件
 *通过容器存放创建的对象,每一个bean名称对应唯一的对象,实现单例,提高运行效率
 * @author xmy
 */
public class BeanFactory {
    //定义一个Properties对象
    private static Properties props;
    //使用静态代码块为Properties对象赋值
    static {
        try {
            //实例化对象
            props = new Properties();
            //获取properties文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getSystemResourceAsStream("Bean.properties");
            props.load(in);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError("初始化properties失败");
        }
    }

    /**
     * 根据bean的名称获取对象
     * @param beanName
     * @param <T>
     * @return
     */
    public static <T> T getBean(String beanName){
        public static <T> T getBean(String beanName){
        T bean = null;
        try {
            String beanPath = props.getProperty(beanName);
            bean = (T) Class.forName(beanPath).newInstance();//每次都会调用默认构造函数创建对象
        }catch (Exception e) {
			e.printStackTrace();
		}
        return bean;
    }
}

resource目录下创建一个Bean.properties文件,配置内容如下:

accountService=com.xmy.service.impl.AccountServiceImpl
accountDao=com.xmy.dao.impl.AccountDaoImpl

CilentAccountServiceImpl类中的通过new对象的形式获取对应接口子类的实例改为使用BeanFactory工厂获取Service和Dao层的实例。如下:

IAccountService as = BeanFactory.getBean("accountService");
private IAccountDao accountDao = BeanFactory.getBean("accountDao");

通过工厂模式分别获取业务层和持久层的实例,解除了各层之间的依赖,降低了耦合性,在这种情形下,即使我们移除AccountDaoImpl类或者AccountServiceImpl类,也不会导致编译错误,这样,如果将来需要替换某一层时,只需要在完成替换后对Bean.properties配置文件进行相应的修改即可,而不需要对原有的程序代码进行修改,降低了维护成本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值