使用Java开发Domino业务应用的设计模式 (cont. 2)

    技术2022-05-20  40

    开发 Library

    “checkout book” 和“delete book”的用例如下:

    Checkout book

    说明:一个member能借出一项资源。Library记录借出的日期,而且要求member在预定的日期(dueDate)内返回资源。

    前提条件:

    Member在library中进行注册

    Member没有走出归还日期仍没有归还的书

    Member所借出的资源不走出5本

    Book现有没有被借出

    完成结果:

    资源被member借出

    资源预定归还日期已设定

    资源借出日期已记录

    Delete book

    说明:管理者可以从library中删除book

    前提条件:

    Book当前没有被借出

    完成结果:

    Book被永远从library中删除

    Delete member

    说明:管理员可以从library中删除member

    前提条件:

           当前member没有借出任何资源

    完成结果:

    Member被永远从系统中删除

    使用 MVC 实现借书( checkout )

    MVC应用流程如图1所示,checkout的事务处理从controller开始。图书馆中的每本书者由一个Notes文档来表示,代表书的Notes文档的unid提交至checkInOut代理(controller),由代理对checkout事务进行调用,因为每个代理都有一定数量的初始化和结束代码,所以减少代码数就是减少维护量.由此,仅用一个checkInOut控制器处理checkout和checkin操作。

    Action参数决定了执行是checkout还是checkin。多个固定在单个控制器上也是J2EE中的一个普遍应用。

    事务由book表单上的action进行调用。Action传送一个HTTP get请求,如:

    http://192.168.1.10/library.nsf.checkInOut?OpenAgent&action=out&unid=XXXXXXXXXXXX 。

    checkInOut 代理的代码如下列表1。其执行了如下的任务:

    public class Agent_CheckInOut extends AgentBase{

           public void NotesMain{

    try{

    Session session = getSession();

    AgentContext agentContext = session.getAgentContext();

    Document docContext = agentContext.getDocumentContext();

    Database dbCurrent = agentContext.getCurrentDatabase();

     

    //get params

    HTTPAgentRequest request = new HTTPAgentTRequest(docContext);

    String strUNID = request.getParameter(“unid”);

    String strAction = request.getParameter(“action“);

     

    //get book document

    Document docBook = dbCurrent.getDocumentByUNID(strUNID);

     

    //create Book document

    Book book = new Book(docBook);

     

    //create member business

    //object for current user

    Member member = Member.createMemberFromCurrentUser();

     

    //perform check in or out

    //based on action param

    if(strAction.eqauals(“out”)) book.checkOut(member);

    else if(strAction.equals(“in”)) book.checkIn();

     

    //redirect user to book in read mode

    String strUrl = book.getReadModeURL();

    getAgentOutput().println(”[” + strUrl + “]”);

     

    }catch (Exception e){

    ExceptionHAndler.handleException(e);

    }

    }

    }

    1、              从查询字符串中读取action和unid。HTTPAgentRequest是作为一个Helper class类(模仿HttpServletRequest)以更易获取查询字符串。

    2、              通过unid找到相应的Notes文档。这就是将要被checkout的book文档。

    3、              根据book文档创建一个book业务对象。

    4、    根据生成代表当前web使用者的member对象的静态方法创建一个Member业务对象。CheckOut代理需要启用“作为Web用户运行代理”的设置。

    5、    对book对象调用checkOut()方法,作为当前使用者checkout这本书。这就是调用 model层所产生的效果。

    6、    checkOut()完成之后,代理使book文档对使用者为只读状态。getReadModeURL() 是在BusinessDocument基类中定义的helper method,返回一个原始Notes文档的只读状态的Document URL。这就是调用View层所产生的效果。

     

    book.checkOut()方法执行了如下的任务:

    1、  分别为checkout时间和due时间创建lotus.domino.DateTime对象。

    2、  写入新的域值checkout。Library中的每一篇文档都拥有一个唯一的关键字,叫做docID,它是对创建文档时所生成的UNID的稍加更改的计算值。为把book和需要借书的member联系起来,book中存储了member文档的DocID。通过这种方式,每一本book都可以找到借出它的member,而且每一个member也可以找到各自借出的book。

    3、  保存文档save()虽然实质上就是执行了标准方法doc.save(true,false),但其中也包括在服务器文档中已启用“允许运行当前代理”的条件下某些用来构造线程安全(thread-safe)的逻辑。在业务对象初始化这段时间内,如果文档已经更改,那么save()方法将操作失败(抛出一个异常)。由于save()是由基类(BusinessDocument)来实现的,所以所有业务对象都拥有安全的特性。

    checkout()方法如列表2。

    使用 Factory 和 Objectifier 模式调用公共方法

    Member和book都拥有deleter()方法,这些方法都对BusinessDocument的delete()方法进行了重载。许多应用都拥有如deleter()和webQuerySave()这样的多个业务对象所共有的公共方法。你可使用Factory和objectifier模式使控制器(agent/servlets)可以有效地使用这些函数。

    在到程序执行才能知道对象类型(类)的情况下,你可以使用Factory模式来进行对象的创建。你可以使用带有创建对象的静态方法的类来实现这个模式,其他类仅仅是调用这个静态方法来创建对象。

    public void checkOut(Member member) throws Exception{

        //compute new dates

        DateTime dtOut = _global.getSession().createDateTime(new java.util.Date());

        DateTime dtDue = _global.getSession().createDateTime(new java.util.Date());

     

        dtDue.adjust(14);

     

        //perform check-out

        _doc.replaceItemValue("Status",STATUS_OUT);

        _doc.replaceItemValue("MemberName",member.getDoc().getItemValuteString("UserName"));

        _doc.replaceItemValue("MemberID",member.getDoc().getItemValueString("DocID"));

        _doc.replaceItemValue("DateOut",dtOut);

        _doc.replaceItemValue("DateDue",dtDue);

        save();

    }}

     

    列表3:

     

    public final class BusinessObjectFactory {

     

        public static BusinessDocument createBusinessObject(Document doc) throws Exception{

           //get form name

           String strForm = doc.getItemValueString("Form");

     

           //init return object

           BusinessDocument bdoc = null ;

     

           //create appropriate BusinessDocument subclass

           //based on form name. Create a BusinessDocument if

           //no class applies.

           if (strForm.equals(Global.FORM_BOOK))

               bdoc = new Book(doc);

           else if (strForm.equals(Global.FORM_MEMBER))

                  bdoc = new Memeber(doc);

               else

               bdoc = new BusinessDocument(doc);

     

           return bdoc;

        }

     

    }

    根据Notes文档的数据,你可以使用Factory模式创建一个业务对象(book或member)。BusinessObject Factory返回一个book或member对象,并把这个对象作为BusinessDocument的一个可变类型。在面向对象语言中(包括面向对象LotusScript),你可以在定义了超类的任何地方使用子类,因为子类一定拥有超类所有的公共属性和方法。

    BusinessObjectFactory代码如列表3。

    Objectifier模式允许一个子类对所有给的函数进行选择性重载,以执行这个函数的待定需求。在这个模式中,定义方法来调用表示父类类型的变量,但这个子类是在runtime时确定的,并对这个方法进行了重载以执行选定的需求。

    首先,看看在不同使用这些模式的时候是如何调用delete()方法的。似通过个Delete代理处理member和book的删除操作,代码如列表4。

    列表 4:

    。。。

    //get document and form

    Document doc = dbCurrent.getDocumentByUNID(strUNID);

    String strForm = doc.getItemValueString("Form");

     

    //instantiate appropriate object based on form and perform deletion

    if(strForm.equals(Global.FORM_BOOK)){

           Book book = new Book(doc);

    }else if(strForm.equals(Global.FORM_MEMBER)){

          Member member = new Member(doc);

    member.deleter();

    }

    使用Factory和objectifier模式完成相同的任务,代码如列表5。

    列表5:

    //Create business object

    Document doc = dbCurrent.getDocumentBUNID(strUNID);

    BusinessDocument bdoc = BusinessObjectFactory.createBusinessObject(doc);

     

    //perform deletion

    bdoc.delete();

    BusinessObjectFactory.createBusinessObject(doc)返回一个book或member对象,且的对象为超类BusinessDocument的一个变量类型。它对delete()进行调用。

    除了代理中只需较少的代码之外,使用这些模式的好处主要体现在维护上。第一种方法中,form-to-business-object的匹配过程体现在代理中。当你需要在应用中增加新的对象类型,例如video,你必须更新为个匹配过程。而且,另一个执行公共任务(如webQuerySave())的代理也必须包含同样的匹配过程。把Factory和Objectfier相结合,你就可以随意 增加或删除新的文档类型,而不用对代理作出修改。

    表3 : library 执行所有的方法和过程

    用例

    执行过程

    创建 book

    更新 book

    注册 member

    更新 member

    l  文档的创建与更新通过表单和webQuerySave代理来处理。库对所有的表单都使用一个WebQuerySave代理

    l  在文档被保存时,代理使用factory和objectifier模式对相应的业务对象调用 webQuerySave()

    l  业务对象能够对webQuerySave()进行重载,以执行对业务对象的验证或操作

    l  Member和Book中的webQuerySave()方法都确保创建和更新的用例的预处理应在保存进程进行之前。

    删除 book

    删除 member

    l  Delete代理(作为MVC删除控制器)使用Factory和Objectifier模式对于已经建立的member或book对象调用delete()

    l  book和member类的deleter()方法使各自的预处理生效,并调用 super.delete()执行删除。

    Checkout book

    Checkin book

    Checkout代理(作为进行checkout和checkin的模式MVC控制器)创建book对象,并根据所得参数“action”的值来调用checkout或checkin方法

    其他用例的实现

    表3 总结了library执行所有用例的方法和过程。

    设计模式的力量

    MVC设计模式把表现层代码从业务逻辑中分离出来,Domino中使用MVC可以简化对UI的维护并为应用功能提供了可选的多界面。

    Domino应用可以通过某些某些机制(包括ODBC和JDBC驱动器)使它们的数据对于其它系统可用。赋闲的,MVC模式可以使应用实现的功能对于系统可用,除了为web浏览器服务之外,应用可以向web services、WAP、CORBA和其它多种类型的客户端提供服务。

       虽然有很多途径用来组织model层,但是通过使用一个java类且表现出现实世界对象的模式是最好的选择。J2EE中,现实世界的对象通过 enterprise session beans和enterprise entity beans来表现,enterprise session beans包含业务逻辑,而enterprise entity beans包含持久数据。在Domino中,业务对象包含了业务逻辑,Notes文档包含了稳定的数据。

       如果使用业务对象实现编码,对于越复杂的应用,你将会得到 越多的益处。业务对象能够封装与现实世界的对象相关的所有任务和业务规则。与现实世界对象相关的功能代码不 能在不同的代理里面进行跨跃。

       把代码封装进一个对象之后,你可以使用熟悉的设计模式来解决公共问题,对于调用多业务对象(例如删除、更新或批准操作)的公共操作,Factory和Objectifier模式提供了很有效的方法。


    最新回复(0)