考虑在你的程序中集成 picocontainer或spring...框架


 

ok,前面的方法可以使单元测试更容易些,下面来看看更酷的:集成pico让程序更简洁。

picoContainer为何物?大家可以google上找一下,连接很多。

我们只说明一下它在我们的程序中的作用并用下面的代码来展现它的可爱之处:

集成pico之后的webwork与上一部分的图示只有一点点不同,就是在实例化Action时,它会查找注册到picoContainer本身的组件,也就是注册到pico中的UserDao,并根据匹配的构造器初始化Action类,即执行new LoginAction(userDao)然后调用Action.execute().就这一点点的不同,让我们看看对我们的构造器注射方式的代码产生了些啥变化。

LoginAction 类:去掉了缺省的构造器。

import webwork.action.ActionSupport;
import ftsmen.dao.UserDao;
import ftsmen.entity.User;

public class LoginAction extends ActionSupport {
    private String username;
    private String password;
    private UserDao userDao ;

    public LoginAction(UserDao userDao) {
	//依赖对象在外部初始化
        this.userDao = userDao;
    }

    //为了程序的简单,假设用户总是已经注册过的
    public String execute() {
	User u = userDao.load(getUsername());
	if (!u.verifyPassword(getPassword())) {
	    //密码错误;
	    return ERROR;
	}
	//验证通过......可以把用户信息放在session中
	    return SUCCESS;
    }

    public String getUsername() {
	return username;
    }
    public void setUsername(String string) {
	username = string;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String string) {
	password = string;
    }
}                

测试类:没有变化

public class LoginActionConstructorInjectionTest extends TestCase {
    public void testLogin() throws Exception {
        LoginAction  action = new LoginAction(new UserDao() {
	   public User load(String username) {
	       User u = new User(username);
	       u.setPassword("chen");
	       return u;
	   }
        });

        action.setUsername("chen56");
        action.setPassword("chen");
        assertEquals("正确登陆", Action.SUCCESS, action.execute());
    }
}
                

UserDao总有被初始化的时候,ok,现在我们把初始化工作集中在一个WebContainerComposer中,并且在web.xml中用context-param描述它,这样,pico就可以根据pico容器中相应的UserDao组件初始化UserAction类了.

package ftsmen.web.action;

import org.picocontainer.MutablePicoContainer;
import org.picoextras.integrationkit.ContainerComposer;

import ftsmen.dao.UserDao;
import ftsmen.dao.HibernateUserDao;
import ftsmen.db.Database;

public class WebContainerComposer implements ContainerComposer {
    String _nameStr;
    public void composeContainer(MutablePicoContainer container, Object name) {
	_nameStr = name.toString().toLowerCase();
	if (isScope("application")) {
	    //可以把scope为application的组件注册到这里
	} else if (isScope("session")) {
	    //可以把scope为session的组件注册到这里
	} else if (isScope("request")) {
            //可以把scope为request的组件注册到这里
            //真实程序中Hibernate的Dao实现用Session来初始化
	    container.registerComponentInstance(
                new HibernateUserDao(Database.currentSession()));
            
            /*jdbc实现可能象这样
            container.registerComponentInstance(
                new JdbcUserDao(Database.connection()));
            */	
        }
    }
	
    private boolean isScope(String scope) {
	return _nameStr.indexOf(scope) != -1;
    }
}            

可以看到,集成pico后的源代码更洁净了,并且Factory的依赖也消除了。

还有什么比清洁溜溜的代码更说明问题呢?

具体集成pico和webwork的方法可以参照
http://www.opensymphony.com/webwork/cookbook/PicoContainer_Integration.html

但其中的WebContainerAssembler类的实现现在已经有所变化,在2004年2月2日左右的实现已经变为我给出的写法。

以上实现并不表明pico只支持构造器注射,实际上目前2个主要的框架spring和pico都支持构造器和setter注射。

 

总结:用pico或spring这样的东东可以迅速的提高程序依赖方面的质量,你不想试一下吗?

资源:

关于作者:

陈鹏,狂热的程序员 email [email protected]