绪论

最近使用 MVC 模式实在是不能自拔,同时也导致出现一列的问题:高耦合。
每个程序猿谈到程序如何设计才好的时候,基本上张嘴就来:高并发、低耦合、高内聚......
那么问题来了,什么是耦合?如何实现低耦合?

耦合

耦合就是对模块间关联程度的度量。简单来说就是个程序之间的依赖程度,包括类之间的依赖、函数之间的了依赖。

栗子

我们有这么一个场景,需要实现一个账户保存的功能。这个很简单,无非就是两个接口、两个实现类、再加一个测试类的事情。

整个功能的包结构

包结构

上代码

Talk is cheap, show me the code;
  • 创建账户持久层接口 IAccountDao,定义保存账户抽象方法
public interface IAccountDao {

    /**
     * 保存账户
     */
    void saveAccount();
}
  • 实现账户持久层酒楼 AccountDaoImpl,并创建并实现 saveAccount 方法,输出保存信息。
public class AccountDaoImpl implements IAccountDao {

    @Override
    public void saveAccount() {
        System.out.println("已保存账户~!");
    }
}
  • 定义账户业务层接口 IAccountService,并定义一个保障账户的方法
public interface IAccountService {

    /**
     * 保存账户
     */
    void saveAccount();
}
  • 实现账户业务层接口 AccountServiceImpl,实现调用持久层 saveAccount 方法实现保存账号抽象方法。
public class AccountServiceImpl implements IAccountService {

    /**
     * 持久层对象
     */
    private IAccountDao accountDao = new AccountDaoImpl();

    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}
  • 最后编写表现层 AccountDemo,测试下该用例是否能正常运行(肯定能,这步是多余的),贴代码了
public class AccountDemo {

    public static void main(String[] args) {
        IAccountService as = new AccountServiceImpl();
        as.saveAccount();
    }
}

// 以下为输出结果
已保存账户~!

强势分析一波

那么我们刚刚说的低耦合,在上面的这几段代码中,耦合程度是很高的。为啥说高耦合呢,假若我们不小心删了 AccountDaoImpl ,整个程序都无法通过编译(如图)。那么这时候就需要解耦。

compile excetion

这时候我们的工厂模式也就出来了。

工厂模式解耦

解耦

在实际开发中,耦合是必然存在的,故只能尽量降低依赖,不能消除。
  • 一般的解耦的思路:

      1. 通过反射来创建对象,而避免使用 new 关键字
      1. 通过读取配置文件来获取要创建对象的全限定类名

使用配置文件

使用配置文件可以达到一个目的,就是当我们通过一些固定不变的内容,可以把其抽取出单独保存,通过调用的方式获取其实例(跟常量类的方式无异)。
  • 创建 bean.properties 文件,保存账户业务层实现类的路径 AccountServiceImpl 和账户持久层接口实现类 AccountDaoImpl 信息,具体如下:
accountService=wiki.laona.service.impl.AccountServiceImpl
accountDao=wiki.laona.dao.impl.AccountDaoImpl
  • 使用反射获取相应的对象实例,具体代码如下:
/**
 * @description: Bean对象的工厂模式
 * @author: laona
 **/
public class BeanFactory {

    /**
     * Properties 对象
     */
    private static Properties props;

    /**
     * 静态代码块为 Properties 对象赋值
     */
    static {
        try {
            // 实例化对象
            props = new Properties();
            // 获取 properties 文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
        } catch (IOException e) {
            throw new ExceptionInInitializerError("初始化 properties 文件异常!");
        }
    }

    /**
     * 获取对象实例
     * @param beanName 对象实例名
     * @return {@link Object} 对象实例
     */
    public static Object getBean(String beanName) {
        Object bean = null;
        try {
            String beanPath = props.getProperty(beanName);
            bean = Class.forName(beanPath).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return bean;
    }
}
  • 那么这时候,账户业务层实现类就可以这么写:
public class AccountServiceImpl implements IAccountService {

    // 通过工厂模式获取 AccountDaoImpl 的实例
    private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");

    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}
  • 表现层这么写:
public class AccountDemo {

    public static void main(String[] args) {
//        IAccountService as = new AccountServiceImpl();
        IAccountService as = (AccountServiceImpl) BeanFactory.getBean("accountService");
        as.saveAccount();
    }
}
这样整个包结构就变成了这样:
new AccountDemo
  • 这时候相比之前耦合程度就大大降低了,这时候尽管删除持久层包下的实现类 AccountDaoImpl,编译是不会出错,但是没有该类是肯定运行不了。编译器会报 java.lang.ClassNotFoundException 异常,而不是 Error。

总结

耦合只是相对而言,工厂模式也不是完美的,仍然存在很多可以优化的地方,但是可以减少部分耦合就是对程序性能的一个大幅度的提升。

老衲
29 声望0 粉丝