关于反射
反射的定义(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
欢迎关注我的微信公众号:窥豹