关于反射

反射的定义(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中。


原文链接: Java笔记 使用反射来改进BaseDao | Log4D

3a1ff193cee606bd1e2ea554a16353ee

欢迎关注我的微信公众号:窥豹

窥豹