精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>● 系统分析>>Value Object(值对象) 模式

主题:Value Object(值对象) 模式
发信人: yife()
整理人: majorsun(2001-12-13 18:22:32), 站内信件
kevin Yee

本文参考了SUN blueprint 模式站点中有关 Value Object(值对象)阐述[英文原文],向大家介绍一种 用粗粒度的数据对象传输 来 提高远程传输效率 的EJB配套 设计模式.该模式有效减轻了 以往翻复的 远程调用,减少了 网络的传输......


值对象 是使用 粗粒度的数据对象传输 来 提高远程传输效率。

实体 Bean 有时总是会有一大堆 属性变量,比如 用户的联系信息(城市,邮政编码,电话,Email等等),假设一下,如果 用户信息有15个属性,那需要声明 15个 getXXX 方法去 获取这些属性,当所有的用户信息被读取的时候,总共需要在CustomerEJB 中调用15个方法,这样加重了网络传输负担 和 容器的负载。

一种解决的方法是使用粗粒度数据对象来代表这些信息,我们把EJB 中的属性变量整和到一个 数据对象ContactInformation 中,之后该对象序列化后被传输到客户端调用,在那里被逆序列化后被客户解读,可以看出后来的解读过程是客户端对本地对象的操作,而不是对远程EJB 的操作,所以没有占用服务器的工作,减少了资源利用。

下图是操作EJB的属性变量,在使用值对象前后的对比



从图中我们可以看出后者 在读取 city, state zipcode等细粒度的变量时没有直接 操作 远程的 EJB ,而是一次性请求 EJB返回 一个 粗粒度的 CustomInfo对象 ,在本地 解析该 对象 返回细粒度的变量。这就是所谓的 值对象模式.

下图就是 值对象的结构图 :



需要注意的是 值对象 虽然是商业逻辑对象,但他只包含了如何解析 值对象 方法,如何构成这些信息 是EJB的工作.

应用值对象,我们应注意:

1.值对象 包含 一组私有变量 和一些获取这些变量相应的方法,他必须是可序列化的(要实现Serializable接口或者 提供方法 可以把变量 转化成可序列化 的对象,比如String),这样 EJB才能把它序列化。

2.值对象是只读的,他只是用于读取EJB的属性变量,我们不可能对他操作来改变 实体 EJB.不过我们可以创建一个新的值对象 ,把他作为远程EJB对象的一个创建参数 来更改 实体EJB的属性变量.这样做其实是把所有的改动一起传递给EJB,而不是象以往那样多次的调用远程方法来更改每一个属性.

3.考虑避免采用 过大的值对象 ,值对象本来就是为了减轻网络传输负担,所以需要 拆分 大的值对象.

4.在EJB2.0规范下使用值对象。在EJB2.0中 提出了依赖性值类(dependent value class),如果把实体Bean 看成是 数据库中一条(行)数据的话 ,依赖性值类就代表了一行数据 的 其中几列,这样 一个实体Bean 就可以表示成 几个 值对象,并且在 CMP 实体Bean 中需要 提供accessor (例如 getXXX) 和 mutator (例如  setXXX) 这样的方法来 读取和改写 值对象。很明显,accessor(getXXX)返回的是值对象 ,mutator(setXXX)把值对象作为参数 传入来改写 相应的数据.

范例代码:
我们看一下 在SUN的 java pet store范例中 做 实体 EJB数据 update 的 相应代码:
当从 一个 更新帐号信息的 jsp (editaccount.jsp) 提交了 更新请求 ,该请求由 web层的 AccountHandler 处理:

public class AccountHandler extends RequestHandlerSupport {

    public EStoreEvent processRequest(HttpServletRequest request)
        throws EStoreEventException {
        // ...

        String action = request.getParameter("action");
        if (action == null) {
            return null;
        } else if (action.equals("createAccount")) {
            return createNewAccountEvent(request);
        } else if (action.equals("updateAccount")) {
            return createUpdateAccountEvent(request);
            // ...
        }
    }

createUpdateAccountEvent来把提交的信息封装成 contactInformation 值对象,并传送给 下一个处理

    private EStoreEvent createUpdateAccountEvent(HttpServletRequest request) {
        // ...

        AccountEvent event = new AccountEvent();
        // ...

        ContactInformation contactInformation 
            = extractContactInformation(request);
        // ...

        event.setInfo(userId, contactInformation, explicitInformation);
        // ...then Ejb will do with the contactInformation 
    }
}

EJB 层的  AccountHandler 来处理 更新操作,注意 CustomerEJB.changeContactInformation() 的参数 是 ContactInformation ,它由 ae.getContactInformation() 得到.


public class AccountHandler extends StateHandlerSupport {

    public void perform(EStoreEvent event) throws EStoreEventException {
        AccountEvent ae = (AccountEvent)event;

        switch (ae.getActionType()) {
        // ...

        case AccountEvent.UPDATE_ACCOUNT: {
            try {
                CustomerHome home = EJBUtil.getCustomerHome();
                Customer cust = home.create();
                cust.changeContactInformation(ae.getContactInformation(),
                                              ae.getUserId());
                // ...

可以看出 以前 多次的 setxxx 的远程调用 被 现在一次 changeContactInformation() 替代了.


(图片源自java.sun.com)

source:
http://www.javadigest.net/index.php?newlang=zho

注:以上文章如果有不当之处,大家可以在阅读英文原文之后,给予指正

[关闭][返回]