让域对象(Domain Object)纵穿整个系统

来源:互联网 发布:淘宝更改绑定手机号 编辑:程序博客网 时间:2024/05/15 15:22

——结合使用Webwork2Hibernate简化系统结构、提高开发效率

引子

如果狭隘的理解,很多时候,一个运行于B/S平台的业务系统的工作是接受用户从浏览器端输入的信息,经过处理后存储到数据库,或者,从数据库提取数据处理并格式化后传回浏览器显示给用户。然而,让应用设计者很沮丧的是:浏览器功能很弱,只能提交复杂度极低的信息,如携带着文本信息的表单(form);主流的数据库是关系数据库,并不能直接存储面向对象的领域模型数据;而应用系统往往是用面向对象的方式来设计、开发的。从只能传递简单数据类型的form,到面向对象的系统,再到关系数据库,都要跨越恼人的系统边界,也就是,我们都要对同一数据进行多次形态转换才能实现系统功能。为了解决这个问题,系统设计先辈提出了很多解决方案,如:用FormBean封装从浏览器传递过来的简单类型数据(也可能进行一些常见类形状换,但说到底,还是简单类型的堆砌,并不是领域模型domain model),用VO(不同的设计叫法不同,但思想是一样的)来对关系数据库做tables—JavaBeans的一对一映射等。

这种方式对浏览器的Form和关系数据库的Table进行了面向对象的封装,从某种意义上讲,起到了一个适配器的作用,在一定程度上隐藏了浏览器的form和数据库的table的底层信息,简化了系统设计,并在相当长的一段时期内取得了很好的效果。但是,随着业务系统需求复杂度的增加,这种解决方案显示出了诸多缺陷:

由于在系统中引入FormBeanVO这两类与domain object无关的对象,分散了开发人员对领域对象本身的关注,增加了系统的复杂度,降低了系统的运行效率,并对系统的耦合度、复用等带来负面的影响。可以认为,这已不再是最好的、最有效的解决方案,我们有必要对这种处理方式进行改进。

 

入题

近年,已经出现了很多成熟的解决方案:

OGNL(http://www.ognl.org)等设置、获取Java Object Properties的语言的出现解决了浏览器等UI系统同核心业务模块交互效果不佳的问题,并且,很多前端控制器(Front controller)很好的实现了OGNL,如WebWork2等;Hibernate(http://www.hibernate.org)O/R Mapping的出现,解决了从对象系统到关系数据库之间的不协调。

于是,在开发中,我们不必被迫在跨越逻辑层次时在不同的JavaBeans之间进行转换。

 

实现

       建立详细细致的业务模型,如:Employee

package info.powersoft.sample;

 

import java.util.Date;

 

/**

 * <p>Description: </p>

 * <p>Copyright: Copyright (c) 2005</p>

 * @author guangzong.xu

 * @since 2005-3-17

 * @version 1.0

 */

 

/**

 * @author guangzong.xu

 *

 * TODO To change the template for this generated type comment go to

 * Window - Preferences - Java - Code Style - Code Templates

 */

public class Employee {

 

       private Long id;

       private String name;

       private Date dateOfBirth;

       private Department department;

       /**

        * @return Returns the dateOfBirth.

        */

       public Date getDateOfBirth() {

              return dateOfBirth;

       }

       /**

        * @param dateOfBirth The dateOfBirth to set.

        */

       public void setDateOfBirth(Date dateOfBirth) {

              this.dateOfBirth = dateOfBirth;

       }

       /**

        * @return Returns the department.

        */

       public Department getDepartment() {

              return department;

       }

       /**

        * @param department The department to set.

        */

       public void setDepartment(Department department) {

              this.department = department;

       }

       /**

        * @return Returns the id.

        */

       public Long getId() {

              return id;

       }

       /**

        * @param id The id to set.

        */

       public void setId(Long id) {

              this.id = id;

       }

       /**

        * @return Returns the name.

        */

       public String getName() {

              return name;

       }

       /**

        * @param name The name to set.

        */

       public void setName(String name) {

              this.name = name;

       }

}

 

Department

package info.powersoft.sample;

 

/**

 * <p>Description: </p>

 * <p>Copyright: Copyright (c) 2005</p>

 * @author guangzong.xu

 * @since 2005-3-17

 * @version 1.0

 */

 

/**

 * @author guangzong.xu

 *

 * TODO To change the template for this generated type comment go to

 * Window - Preferences - Java - Code Style - Code Templates

 */

public class Department {

 

       private Long id;

       private String name;

       private Department superDepartment;

       /**

        * @return Returns the id.

        */

       public Long getId() {

              return id;

       }

       /**

        * @param id The id to set.

        */

       public void setId(Long id) {

              this.id = id;

       }

       /**

        * @return Returns the name.

        */

       public String getName() {

              return name;

       }

       /**

        * @param name The name to set.

        */

       public void setName(String name) {

              this.name = name;

       }

       /**

        * @return Returns the superDepartment.

        */

       public Department getSuperDepartment() {

              return superDepartment;

       }

       /**

        * @param superDepartment The superDepartment to set.

        */

       public void setSuperDepartment(Department superDepartment) {

              this.superDepartment = superDepartment;

       }

}

 

       DAO

package info.powersoft.sample;

 

/**

 * <p>Description: </p>

 * <p>Copyright: Copyright (c) 2005</p>

 * @author guangzong.xu

 * @since 2005-3-17

 * @version 1.0

 */

 

/**

 * @author guangzong.xu

 *

 * TODO To change the template for this generated type comment go to

 * Window - Preferences - Java - Code Style - Code Templates

 */

public interface EmployeeDAO {

 

       Long insertEmployee(Employee employee);

}

 

       使用Webwork2作为前端控制器(front controller),并在相应的action中把该业务模型作为一个变量,设置相应的gettersetter,如

package info.powersoft.sample;

 

/**

 * <p>Description: </p>

 * <p>Copyright: Copyright (c) 2005</p>

 * @author guangzong.xu

 * @since 2005-3-17

 * @version 1.0

 */

 

/**

 * @author guangzong.xu

 *

 * TODO To change the template for this generated type comment go to

 * Window - Preferences - Java - Code Style - Code Templates

 */

public class EmployeeAction {

 

    private EmployeeDAO employeeDAO;

    private Employee employee;

   

    /**

     * @return Returns the employeeDAO.

     */

    public EmployeeDAO getEmployeeDAO() {

        return employeeDAO;

    }

    /**

     * @param employeeDAO The employeeDAO to set.

     */

    public void setEmployeeDAO(EmployeeDAO employeeDAO) {

        this.employeeDAO = employeeDAO;

    }

    /**

     * @return Returns the employee.

     */

    public Employee getEmployee() {

        return employee;

    }

    /**

     * @param employee The employee to set.

     */

    public void setEmployee(Employee employee) {

        this.employee = employee;

    }

   

    public String execute() throws Exception {

        employeeDAO.insertEmployee(employee);

        return "success";

    }

}

       其中,EmployeeDAO是用于将域对象存储到数据库中的DAO,特定实现可以用Hibernate,这个大家都很熟悉,不在此赘述。

    发送到浏览器中的网页为

<html>

<head>

<title>test</title>

</head>

 

<body>

<form name="form1" method="post" action="employee.action">

  <p>

    <input name="employee.name" type="text">

  </p>

  <p>

    <input name="employee.dateOfBirth" type="text">

  </p>

  <p>

    <input name="employee.department.id" type="text">

  </p>

  <p>

    <input type="submit" name="Submit" value="Submit">

  </p>

</form>

</body>

</html>

       我们可以注意到网页中,文本输入框(input type="text")的名字(name)为类似于这样的东西:“employee.department.id”,经Webwork2interceptor的拦截,自动把这些form中的field中的字段拼装成我们所需要的employee对象,供我们方便的调用,省去了在FormBeanDomain Object间的转换。同样的道理,我们也可以把这些域对象送到视图层去格式化显示(这其中要用一些支持特定功能的表示技术,如jsp2.0freemarker等)

 

完了的话

       至此,我们已经完成从浏览器接受输入到存储进数据库,在这过程当中,一直是同一个域对象(Domain Object)承载着应用所需要的信息,没有被迫进行数据转换,代码相对简洁,结构相对明了,同时,执行效率也较传统方式(FormBean->Domain Object->VO)有所提高。

当然,本文只是从梗概上介绍了这种实现方式,所提供的代码并不能直接运行。如果你在体验的过程中有好的想法,或者遇到问题,欢迎与我交流boyxgz@msn.com