分析程序耦合与解耦思路

程序间耦合是指程序之间的依赖关系。我们开发的程序如果耦合度太高就会导致独立性太差,所以软件开发应该遵循高内聚,低耦合的设计标准。依赖一般分为类之间的依赖和方法之间的依赖。那么如何降低程序间的依赖呢?在开发中,应该做到程序在编译的时候不依赖,在运行的时候才依赖,我们可以通过两个步骤来分析实现。

  • 第一:使用反射来创建对象,避免使用new关键字创建;
  • 第二:通过配置文件来获取要创建对象的全限定类名。通过以上两步即可做到完美解耦。

1、程序耦合

案例:

我们做一个模拟保存用户的例子,在有解耦意识之前,我们的代码是这样的:

package cn.com.gjw.dao;
 
//用户持久层接口
public interface UserDao {
	void saveUser();
}
package cn.com.gjw.dao.impl;
 
import cn.com.gjw.dao.UserDao;
//用户持久层接口实现类
public class UserDaoImpl implements UserDao {
 
	@Override
	public void saveUser() {
		System.out.println("模拟保存用户信息。。。");
	}
 
}
package cn.com.gjw.service;
//用户业务层接口
public interface UserService {
 
	void saveUser();
}
package cn.com.gjw.service.impl;
 
import cn.com.gjw.dao.UserDao;
import cn.com.gjw.dao.impl.UserDaoImpl;
import cn.com.gjw.service.UserService;
 
public class UserServiceImpl implements UserService {
 
	private UserDao dao = new UserDaoImpl();
	@Override
	public void saveUser() {
		dao.saveUser();
	}
 
}
package cn.com.gjw.test;
 
import cn.com.gjw.service.UserService;
import cn.com.gjw.service.impl.UserServiceImpl;
 
public class Test2 {
 
	public static void main(String[] args) {
		UserService service = new UserServiceImpl();
		service.saveUser();
	}
}

main函数依赖UserServiceImpl类才能编译成功,同样,UserServiceImplement类依赖UserDaoImpl才能编译成功,足以看出耦合度很高。

2、解耦

那么接下来我们通过解耦来提高程序的独立性:

首先创建一个属性文件(beans.properties),以键值对的形式存放以下内容:

userService=cn.com.gjw.service.impl.UserServiceImpl
userDao=cn.com.gjw.dao.impl.UserDaoImpl

其次再创建一个Bean工厂,由工厂代替new关键字为我们创建对象:

/**
 * 一个创建Bean对象的工程
 *
 *  Bean:在计算机英语中,有可重用组件的含义
 *  JavaBean:用java语言编写的可重用组件。
 *      javaBean > 实体类
 *
 *  它就是用来创建service和dao对象的。
 *
 *  第一个:需要一个配置文件配置我们的service和dao
 *          配置内容:唯一标识符=全限定类名(key = value)
 *  第二个:通过读取配置文件中配置的内容,反射创建对象
 *
 *  配置文件可以是xml也可以是properties
 */
public class BeanFactory {
    //定义Properties对象
    private static Properties props;

    //使用静态代码块为Properties赋值
    static{
        try {
            //1.实例化对象
            props = new Properties();
            //2.获取properties文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("beans.properties");
            props.load(in);

        } catch (Exception e) {
            throw new ExceptionInInitializerError("初始化properties失败!");
        }
    }

    /**
     * 根据Bean的名称获取Bean对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName){
        Object bean = null;
        try {
            String beanPath = props.getProperty(beanName);
            System.out.println(beanPath);
            bean = Class.forName(beanPath).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bean;
    }
}

此时,我们创建对象时,只需要调用BeanFactory类的getBean()方法即可。同时,我们对依赖的类也要做调整:

package cn.com.gjw.test;
 
import cn.com.gjw.factory.BeanFactory;
import cn.com.gjw.service.UserService;
 
public class Test2 {
 
	public static void main(String[] args) {
		//UserService service = new UserServiceImpl();
		UserService service = (UserService) BeanFactory.getBean("userService");
		service.saveUser();
	}
}
package cn.com.gjw.service.impl;
 
import cn.com.gjw.dao.UserDao;
import cn.com.gjw.factory.BeanFactory;
import cn.com.gjw.service.UserService;
 
public class UserServiceImpl implements UserService {
 
	//private UserDao dao = new UserDaoImpl();
	private UserDao dao = (UserDao) BeanFactory.getBean("userDao");
	
	@Override
	public void saveUser() {
		dao.saveUser(); 
	}
 
}

至此,我们已完成程序间解耦,此时,不管程序中缺少UserServiceImpl类还是缺少UserDaoImpl类,程序都能编译通过。

1.1 多例模式转单例

但是我们的Bean现在是多例模式,例如:

	public static void main(String[] args) {
		//UserService service = new UserServiceImpl();
		for(int i = 0; i < 5; i++) {
			UserService service = (UserService) BeanFactory.getBean("userService");
			System.out.println(service);
		}
		//service.saveUser();
	}

打印结果为:
在这里插入图片描述
从打印结果可以看出,我们循环了5次,创建了5次service对象,这会影响我们程序的性能,最好使用单例模式,同样也要注意单例模式带来的多线程问题,因此在使用单例模式时,我们尽量把普通变量定义到方法内部,形成局部变量,对工厂类进行改进:

package cn.com.gjw.factory;
//bean工厂
 
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
 
public class BeanFactory {
 
	private static Properties props;
	
	//程序启动时,将所有的对象创建好,并存入map集合中,使用的时候直接从集合中拿,不需要再创建
	private static Map<String, Object> beans = new HashMap<String, Object>();
	
	//静态代码块,只在程序启动时执行一次
	static {
		try {
			props = new Properties();
			//通过流的方式加载属性文件
			InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("beans.properties");
			props.load(in);
			//从属性对象props中获取所有的键,是一个枚举类型的集合
			Enumeration<Object> keys = props.keys();
			//遍历
			while(keys.hasMoreElements()) {
				String key = keys.nextElement().toString();
				String pathName = props.getProperty(key);
				try {
					Object value = Class.forName(pathName).newInstance();
					beans.put(key, value);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static Object getBean(String beanName) {
		return beans.get(beanName);
	}
	//通过bean的名称获取对象
/*	public static Object getBean(String beanName) {
		//bean的全限定类名
		String beanPath = props.getProperty(beanName);
		Object bean = null;
		try {
			bean = Class.forName(beanPath).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bean;
	}*/
}

打印结果为:

com.study.iocbase.service.UserServiceImpl@61bbe9ba
com.study.iocbase.service.UserServiceImpl@61bbe9ba
com.study.iocbase.service.UserServiceImpl@61bbe9ba
com.study.iocbase.service.UserServiceImpl@61bbe9ba
com.study.iocbase.service.UserServiceImpl@61bbe9ba

此刻,已实现单例模式,并且成功完成解耦。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值