DAO层与Service业务逻辑层的解耦实现之Factory工厂模式

在开始阐述DAO与Service层如何实现解耦之前,我先提一个站在学习者角度的问题,为什么在MVC的三层开发架构中会非常推崇接口编程,那么根据已有的解释,接口编程的好处是:可以帮助层与层之间的解耦,让每个部分独立出来,互不影响,更加的利于团队开发合作和提高复用性与扩展性。那么,在数据访问层(DAO)和业务层(SERVICE)之间的解耦是如何做到的呢?下面请先看一张框架简图:


DAO层与Service业务逻辑层的解耦实现之Factory工厂模式_第1张图片


不难发现的是,UserService是通过接口UserDao来间接操作UserDaoImpl访问Domain对象User中的数据的。有些编程经验的童鞋都应该明白,要想拿到具体的实现,那么这种操作(先不管红色部分的UserDaoFactory工厂类),在访问User时就必定要在UserService中有这样的语句:UserDao  userDao = new UserDaoImpl();  那么,问题来了, UserDaoImpl实现类在这里出现并将导致在后期拓展时(比如UserDao的具体实现改换为Hibernate或者其它技术)就无法真正的做到解耦,因为你必须在你的源代码中指定具体的实现类。如果这里,你还没有明白,那么请看以下代码:


首先,我们来构造一个Domain域对象User,此User在此其实并没有多大意义只是为了展示Domain对象的结构:

package com.jasber.jdbc.test1;

import java.util.Date;

/**
 * This is Bean that corresponding int Mysql database table tb_test
 * 
 * @author Jasber-Yon
 *
 */
public class User {

	private Integer id;
	private String name;
	private Date birthday;
	private Double salary;

	public User() {
	}

	public User(Integer id, String name, Date birthday, Double salary) {
		super();
		this.id = id;
		this.name = name;
		this.birthday = birthday;
		this.salary = salary;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public Double getSalary() {
		return salary;
	}

	public void setSalary(Double salary) {
		this.salary = salary;
	}
}
然后,定义一个数据访问接口UserDao:

package com.jasber.jdbc.test1;

/**
 * 
 * @author Jasber-Yon
 *
 */
public interface UserDao {

	public boolean getUserInfoById(User user);
}
现在,就来实现这个UserDao数据访问接口,实现类UserDaoImpl(在这里就不做真正的实现了,只为说明问题):

package com.jasber.jdbc.test1;

public class UserDaoImpl implements UserDao {

	@Override
	public boolean getUserInfoById(User user) {
		//.....代码省略
		System.out.println("哈哈,我被调用了~");
		return false;
	}

}

那么,现在,我们可以写一个UserService来模拟一下调用了:

package com.jasber.jdbc.test1;

/**
 * 
 * @author Jasber-Yon
 *
 */
public class UserService {

	public static void main(String[] args) {
		User user = new User();
		UserDao userDao = new UserDaoImpl();
		userDao.getUserInfoById(user);
	}

}
现在,就会发现,UserDaoImpl 在UserService中被“点名”了,这样干,显然是不合理的,没有做到真的解耦,我们的目的是,要让 UserService仅仅只需要通过数据访问接口UserDao就做到需要的操作。那么,应该如何来做呢?

一、提供一个工厂类,让他去对具体的实现类进行实例化,并返回UserDao的实现类的实例的引用。

二、这个数据访问接口的实现类在哪儿呢?通过配置文件(XML/Properties,我偷个懒就使用properties文件了)来配置,让工 厂类去读取(或者专用的操作类去读取)。

那么,请看这个工厂类UserDaoFactory的实现:

package com.jasber.jdbc.test1;

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

public class UserDaoFactory {

	private static UserDao userDao = null;// 注意此句必须放在实例化工厂类的语句之前,否者会在运行时被置为null
	private static UserDaoFactory userDaoFactory = new UserDaoFactory();

	private UserDaoFactory() {
		Properties properties = new Properties();
		InputStream inputStream = UserDaoFactory.class.getClassLoader()
				.getResourceAsStream("daoConfig.properties");
		try {
			properties.load(inputStream);
			String userDaoImpl = properties.getProperty("userDaoImpl");
			userDao = (UserDao) Class.forName(userDaoImpl).newInstance();
		} catch (Throwable e) {
			throw new ExceptionInInitializerError(e);// 此问题非常严重
		}finally{
			try {
				inputStream.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public static UserDaoFactory getInstance() {
		return userDaoFactory;
	}

	public UserDao getUserDao() {
		return userDao;
	}
}

通过类加载器,获得到实现类的位置,然后通过反射技术将其实例化。在此工厂(单例实现,懒汉式直接加载,也可延迟加载)类中将提供返回工厂实例的方法以及数据访问接口UserDao的实现类的实例。

现在再来看看,我们是怎样在UserService中来操作数据访问对象(DAO)的:

package com.jasber.jdbc.test1;

/**
 * 
 * @author Jasber-Yon
 *
 */
public class UserService {

	public static void main(String[] args) {
		/*User user = new User();
		UserDao userDao = new UserDaoImpl();
		userDao.getUserInfoById(user);*/
		
		User user = new User();
		UserDao userDao = UserDaoFactory.getInstance().getUserDao();
		userDao.getUserInfoById(user);
		
	}

}
与注释部分对比,不难发现,已经没有了UserDaoImpl的踪影。完全是在操作接口了。是不是就已经解耦了呢?


想必,到这儿,已经明白是怎么回事了。下面在说一说,我在程序中使用到的 daoConfig.properties 文件(我是偷懒了啊,当然这样也是为了简化代码保证阐述问题的单纯性,就没有使用XML来说事),因为我们使用到了类加载器,该配置文件必须要放置在ClassPath路径下(当然位置是随意的,ClassPath路径就是指运行程序时,会被JVM读取加载的目录,也就是bin目录下,Java工程里,使用eclipse的就直接放在src目录下即可,编译时会被自动带过去的),不然就会无法找到该文件而出现空指针异常。

以上就是本篇博客。~博主的肚子好饿~






你可能感兴趣的:(DAO层与Service业务逻辑层的解耦实现之Factory工厂模式)