java降低程序间耦合(解耦)

2022-07-27,,,

程序耦合是指程序之间的依赖关系。我们开发的程序如果耦合度太高就会导致独立性太差,所以软件开发应该遵循高内聚,低耦合的设计标准。依赖一般分为类之间的依赖和方法之间的依赖。那么如何降低程序间的依赖呢?在开发中,应该做到程序在编译的时候不依赖,在运行的时候才依赖,我们可以通过两个步骤来分析实现,第一:使用反射来创建对象,避免使用new关键字创建;第二:通过配置文件来获取要创建对象的全限定类名。通过以上两步即可做到完美解耦。

案例:

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

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才能编译成功,足以看出耦合度很高。

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

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

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

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

package cn.com.gjw.factory;
//bean工厂

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

public class BeanFactory {

	private static Properties props;
	//静态代码块,只在程序启动时执行一次
	static {
		try {
			props = new Properties();
			//通过流的方式加载属性文件
			InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("beans.properties");
			props.load(in);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//通过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;
	}
}

此时,我们创建对象时,只需要调用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类,程序都能编译通过。但是我们的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;
	}*/
}

打印结果为:

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

本文地址:https://blog.csdn.net/qq_25816185/article/details/109838277

《java降低程序间耦合(解耦).doc》

下载本文的Word格式文档,以方便收藏与打印。