Java笔记 使用反射来改进BaseDao

关于反射

反射的定义(via Wiki):在计算机科学中,反射是指一种特定类型的计算机程序能够在运行时以一种依赖于它的代码的抽象特性和它的运行时行为的方式被更改的特性。用比喻来说,那种程式能够“观察”并且修改自己的行为。

Java中的反射示例如下:

package dddspace.job.exercise1116;

public class Foo {

	public void fun(String str) {
		System.out.println(str);
	}
}

package dddspace.job.exercise1116;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionDemo {

	public static void main(String[] args) throws SecurityException,
		NoSuchMethodException, ClassNotFoundException, InstantiationException,
		IllegalAccessException, IllegalArgumentException,
		InvocationTargetException {

		// 不使用反射
		Foo foo = new Foo();
		foo.fun("no reflection");

		// 使用反射
		String className = "dddspace.job.exercise1116.Foo";
		String funName = "fun";
		// 获取类名
		Class cls = Class.forName(className);
		// 创建Object实例
		Object foo2 = cls.newInstance();
		// 创建Method hello
		Method method = cls.getMethod("fun", String.class);
		// 使用反射来调用Method的invode方法,参数是目标对象+参数
		method.invoke(foo, "use reflection");
	}
}

 原始BaseDao设计

我先阐述一下BaseDao的设计想法:BaseDao是一个抽象类,提供一系列Dao方法"get()/getAll()/add()/update()/delete()/getCount()",通过泛型匹配的获取类,我取出一个方法来做示例。

 

public int getCount()
{
	int count = 0;
	Session session = null;
	Transaction tx = null;
	String Tstr = getClass().getSimpleName().substring (0,
			getClass().getSimpleName().length() - 3);
	String hql = "select count(*) from " + Tstr;
	try {
		session = HibernateSessionFactory.currentSession();
		tx = session.beginTransaction();
		Query query = session.createQuery(hql);
		count = Integer.parseInt(query.uniqueResult().toString());
		query = null;
		tx.commit();
	} catch (HibernateException e) {
		if (tx != null) {
			tx.rollback();
		}
		throw e;
	} finally {
		HibernateSessionFactory.closeSession();
	}
	return count;
}

 其中有一段dirty work,就是TStr的获取,这段TStr是想从实现Dao类获取实体类的类型名称,也就是从"TopicDao"获取"Topic"这个类型名称。整个BaseDao的泛型设计不错,但是在这一段上面存在一段dirty work,始终让我不爽。

重构BaseDao和TopicDao

我今天复习完抽象类/接口/反射这些内容,又在纸上画了一个模型,觉得用这种新方法解决会更好一点。

给抽象类BasoDao加入新的变量Class c,然后在TopicDao初始化时候对Class c进行设置为Topic.class,这样就比原来的拼字符串好的多。耦合也显得漂亮了

public abstract class BaseDAO<T> {

	protected Class c;

	private Logger logger = Logger.getLogger(this.getClass());

	/**
	 * 根据某个Bean的beanId取出Bean
	 * @param tId
	 * @return Bean
	 */
	public T get(int tId)
	{
		T t=null;
		Session session = null;
		Transaction tx = null;
		// 原始设计
//		String Tstr = getClass().getSimpleName().substring (0,
//				getClass().getSimpleName().length() - 3);
		// 获取c的名称
		String Tstr = c.getSimpleName();
		String TstrId = Tstr+"Id";
		String hql = "from " + Tstr + " where " +
			TstrId.substring(0, 1).toLowerCase() + TstrId.substring(1) + " = ?";
		try {
			session = HibernateSessionFactory.currentSession();
			tx = session.beginTransaction();
			Query query = session.createQuery(hql);
			query.setInteger(0,tId);
			t = (T)query.uniqueResult();
			query = null;
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null) {
				tx.rollback();
			}
			throw e;
		} finally {
			HibernateSessionFactory.closeSession();
		}
		return t;
	}
public class TopicDAO extends BaseDAO<Topic>{

	private Logger logger = Logger.getLogger(this.getClass());
	/**
	 * 根据froumId取出某一吧内的所有没被屏蔽的帖子
	 * @param froumId
	 * @return ArrayList<Topic>
	 * @throws HibernateException
	 */
	// 在构造函数中进行c的设置
	public TopicDAO () {
		c = Topic.class;
	}
	//doSomething
}

 这样完成之后,就完成了一次简单的重构,实现了变化点分离,而且不那么dirty。

本文的代码来源自PostBar项目。这里有Google Code链接,v1.0.1的代码并没有上文的实现,本文中的修改还在trunk中。

版权所有 © 2010 转载本站文章请注明: 转载自Log4D
原文链接: http://dddspace.com/2009/11/note-the-use-of-java-reflection-to-improve-the-basedao.html
您可以随意地转载本站的文章,但是必须在醒目位置注明来源及本站链接,不可以将本站文章商业化使用,或者修改、转换或者以本作品为基础进行创作。
3a1ff193cee606bd1e2ea554a16353ee

分享家:Addthis中国
相关文章

2 条留言

  1. 被发表在 2009年11月17日 at 09:43 | 固定链接

    好牛的程序

    [回复]

  2. 被发表在 2009年11月17日 at 18:43 | 固定链接

    @卢松松
    呵呵,谢谢,复习时候的一点笔记,如果有人关键字过来,希望能有帮助

    [回复]

留下一条评论

你的邮箱不会被公开 . *标注为必填

*
*