工厂模式解耦

举报
王小艺 发表于 2020/07/31 10:18:58 2020/07/31
【摘要】 作为一个初学者,想要在这方面获得巨大的提升,必然要耐得住寂寞,和源码死磕

作为一个初学者,想要在这方面获得巨大的提升,必然要耐得住寂寞,和源码死磕

工厂模式解耦【一】代码的耦合性分析

  • 创建一个Spring Boot项目

    image.png

  • 目录结构为

    image.png

  • 代码实现为

package cn.itycu.service;

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:06
 * 账户的业务层接口
 */
public interface IAccountService {

    /**
     * 模拟一个保存
     */
    void saveAccount();
}
-----------------------------分割线-------------------------------
package cn.itycu.service.impl;

import cn.itycu.dao.IAccountDao;
import cn.itycu.dao.impl.AccountDaoImpl;
import cn.itycu.service.IAccountService;

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:11
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao = new AccountDaoImpl();

    public void saveAccount() {
        accountDao.saveAccount();
    }
}
-----------------------------分割线-------------------------------
package cn.itycu.dao;

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:15
 * 账户的持久层接口
 */
public interface IAccountDao {

    /**
     * 模拟保存账户
     */
    void saveAccount();
}
-----------------------------分割线-------------------------------
package cn.itycu.dao.impl;

import cn.itycu.dao.IAccountDao;

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:16
 * 账户的持久层实现类
 */
public class AccountDaoImpl implements IAccountDao {

    public void saveAccount() {
        System.out.println("保存一个账户");
    }
}
-----------------------------分割线-------------------------------
package cn.itycu.ui;

import cn.itycu.service.IAccountService;
import cn.itycu.service.impl.AccountServiceImpl;

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:21
 * 模拟一个表现层,用于调用业务层
 */
public class Client {
    public static void main(String[] args) {
        IAccountService accountService = new AccountServiceImpl();
        accountService.saveAccount();
    }
}

通过 表先层 => 业务层 => 持久层 的一个 MVC 三层架构没有问题
但是 表现层在调用业务层时关键的new关键字和业务层在调用持久层时关键的new关键字,就是我们在实际开发中急需解决的问题,因为这样一种逻辑结构具有很强的耦合性使我们的代码独立性很差

工厂模式解耦【二】创建工厂

  • 我们通过创建一个类使BeanFactory使用用工厂模式进行解耦

  • 同时通过bean.properties映射 service 和 dao 对象的全限定类名

package cn.itycu.factory;

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

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:47
 * 一个创建bean对象的工厂
 * Bean:在计算机英语中有可重用组件的含义
 * 通过工厂创建service和dao对象
 */
public class BeanFactory {
    //定义一个properties对象并用static代码块儿对对象进行赋值
    private static Properties props;
    static {
        try {
            //实例化对象,耦合只能减小不能消除,所以必要的new我们还是需要的
            props = new Properties();
            /**
             * 获取properties文件的流对象
             * 使用类加载器来获取bean.properties文本对象
             * 创建在resources目录下的文件最终会成为类根目录下的文件
             */
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
        } catch (Exception e) {
            throw new ExceptionInInitializerError("初始化 properties 失败!");
        }
    }

    /**
     * 根据Bean的名词获取bean对象
     * 采用泛型编程,增加工厂的复用性
     * @param beanName
     * @return
     */
    public 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;
    }
}
-----------------------------分割线-------------------------------
// bean.properties 文件
// accountService=cn.itycu.service.impl.AccountServiceImpl
// accountDao=cn.itycu.dao.impl.AccountDaoImpl
-----------------------------分割线-------------------------------
package cn.itycu.ui;

import cn.itycu.factory.BeanFactory;
import cn.itycu.service.IAccountService;
import cn.itycu.service.impl.AccountServiceImpl;

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:21
 * 模拟一个表现层,用于调用业务层
 */
public class Client {
    public static void main(String[] args) {
//        IAccountService accountService = new AccountServiceImpl();
        IAccountService accountService = (IAccountService) BeanFactory.getBean("accountService");
        accountService.saveAccount();
    }
}
-----------------------------分割线-------------------------------
package cn.itycu.service.impl;

import cn.itycu.dao.IAccountDao;
import cn.itycu.dao.impl.AccountDaoImpl;
import cn.itycu.factory.BeanFactory;
import cn.itycu.service.IAccountService;

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:11
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

//    private IAccountDao accountDao = new AccountDaoImpl();
    private IAccountDao accountDao = (IAccountDao)BeanFactory.getBean("accountDao");
    public void saveAccount() {
        accountDao.saveAccount();
    }
}


这样我们就实现了工厂模式解耦
但是我们的代码中仍然存在一些问题

工厂模式解耦【三】分析工厂模式中的问题并改造

我们修改一下代码并输出观察

package cn.itycu.ui;

import cn.itycu.factory.BeanFactory;
import cn.itycu.service.IAccountService;
import cn.itycu.service.impl.AccountServiceImpl;

/**
 * @author 披风少年
 * @version 1.0
 * @date 2020/5/23 15:21
 * 模拟一个表现层,用于调用业务层
 */
public class Client {
    public static void main(String[] args) {
//        IAccountService accountService = new AccountServiceImpl();
        for (int i = 0; i < 5; i++) {
            IAccountService accountService = (IAccountService) BeanFactory.getBean("accountService");
            System.out.println(accountService);
        }
//        accountService.saveAccount();
    }
}
-----------------------------输出结果-------------------------------
"C:\Program Files (x86)\Java\jdk1.8.0_144\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=26505:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\rt.jar;C:\Users\15402\Desktop\demo01\target\classes" cn.itycu.ui.Client
cn.itycu.service.impl.AccountServiceImpl@a14482
cn.itycu.service.impl.AccountServiceImpl@140e19d
cn.itycu.service.impl.AccountServiceImpl@17327b6
cn.itycu.service.impl.AccountServiceImpl@14ae5a5
cn.itycu.service.impl.AccountServiceImpl@131245a

Process finished with exit code 0

我们发现对象 accountService 是多例的,每一次请求都会创建一个新的对象,执行效率肯定没有单例对象高。
我们采用map在初始化时创建对象,这样就不用反复创建对象了,修改代码如下



我们发现输出五次都是同一个对象


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。