RunBase saveLast and serialization

来源:互联网 发布:秦凯何姿 知乎 编辑:程序博客网 时间:2024/06/06 06:32

继承自RunBase的所有类,都可以定义一个#CURRENTLIST宏,这个宏有两个用途:

1.       装载用户上次使用该类时所输入的数据

2.       用于实现序列化类

实现这些功能,用户必须重写packunpack方法。

 

如果#CURRENTLIST保存的数据可以实现序列化,但如果我们只想保存#CURRENTLIST中的部分值,这些值在用户下次打开该类时自动装载,又该怎么办呢?

举个例子,现在有一个类:

Class Test extends RunBase

{

CustAccount         custAccount;

    CustInvoiceAccount  invoiceAccount;           

#DEFINE.CURRENTVERSION(1)

           #DEFINE.VERSION1(1)

           #LOCALMACRO.CURRENTLIST

                    custAccount,

                    invoiceAccount

                   #ENDMACRO

}

对应的Dialog如下图:

dialog

custAccount invoiceAccount是序列化Test类是必须的数据,但我只想让Customer account的值被系统自己记忆。

 

本文首先分析系统如何实现功能12,然后来解决我们在上面所提到的问题。

 

RunBase是一个抽象类,它继承自类Object,同时实现了两个接口类SysSaveableSysRunable

SysSaveable接口又继承自接口SysPackable.

这些类和接口所拥有的方法如下图所示(RunBase所拥有的方法没有列出了):

runbase

 

 

Q1:为什么宏的名字是#CURRENTLIST

 

RunBase的声明中有这样一段代码:

#if.never

             #define.CurrentVersion(1)

             #define.version1(1)

             #localmacro.CurrentList

             #endmacro

#endif

而在RunBasepack方法中,有这样的代码:

#if.never

             return [#CurrentVersion,#CurrentList];

#endif

RunBaseunpack方法中,是这样写的:

#if.never

             Version version     = runbase::getVersion(packedClass);

             switch (version)

             {

                 case #CurrentVersion:

                     [version,#CurrentList] = packedClass;

                     break;

                 default:

                     return false;

             }

             return true;

#endif

 

所以,如果你要问为什么继承自RunBase的类要定义#CurrentVersion,#CurrentList这样的宏,原因就是父类是这样写的,所以大家很自然就定义了同样名字的宏来使用。

在重写子类的packunpack时,你完全可以定义这里个宏为其它名字,如#MYCURRENTVERSION,#MYCURRENTLIST,如:

Class Test extends RunBase

{

CustAccount         custAccount;

    CustInvoiceAccount  invoiceAccount;           

#DEFINE.MYCURRENTVERSION(1)

           #DEFINE.VERSION1(1)

           #LOCALMACRO.MYCURRENTLIST

                    custAccount,

                    invoiceAccount

                   #ENDMACRO

}

 

Public container pack()

{

         Return [#MYCURRENTVERSION,#MYCURRENTLIST];

}

 

public boolean unpack(container packedClass)

{

    boolean ret = true;

    Version version = Runbase::getVersion(packedClass);

    container packedQueryRun;

    ;

    switch (version)

    {

        case #MYCurrentVersion:

            [version,#MYCurrentList,packedQueryRun] = packedClass;

            if (SysQuery::isPackedOk(packedQueryRun))

            {

                queryRun = new QueryRun(packedQueryRun);

            }

            break;

        default:

            ret = false;

            break;

    }

    return ret;

}

 

Q2: RunBase的基本调用流程是什么

liucheng

现在我们来回答文章一开始提的知识点1:装载用户上次使用该类时所输入的数据

         RunBase的子类完成new之后,直接调用Prompt方法,该方法会最终调用到getLast方法,getLast方法根据version,areaId,userId,typename来查询上次的值(name是保存对象的类名,type是保存对象的类别,如report),然后试图unpack查询到的结果,如果unpack失败,则调用InitParmDefault来赋值。然后显示Dialog.

         Dialog成功关闭后(即点OK关闭),判断当前对象是否是从服务器产生过来的,如果是,就不做saveLast,因为服务器端会做这一步。如果不是,则在客户端做saveLast,通过pack来完成这一动作。

然后是文章一开始提到的知识点2:用于实现序列化类

         如果RunBase的某个子类运行在服务器端,而要求其Dialog是在客户端运行,那么系统会使用如下的代码:

// Move prompt to client when running on server and the class is swappable

if (isRunningOnServer() && this.canSwapBetweenCS() && this.canSwapBetweenCSPrim())

{

 [clientPrompt,clientPacked] =RunBase::promptOnClient(classidget(this),this.promptPack());

 this.promptUnpack(clientPacked,clientPrompt);

 if(clientPrompt)

   this.saveLast();

 return clientPrompt;

}

 

PromptPack方法会调用pack方法,promptUnpack方法会调用unpack方法。

RunBase::promptOnClient(classidget(this),this.promptPack());使Dialog在客户端显示,在Dialog关闭后,Dialog会将数据pack起来以返回值的形式传递进来,我们使用容器:

[clientPrompt,clientPacked]将数据接收,再通过promptUnpack调用unpack来重写赋值数据。

 

如何解决我们在文章开头提到的问题?

 

SaveLastGetLast时,我们不再使用packunpack 而是定义新的专门为savelastgetLast服务的unpackSysLastValuepackSysLastValue方法。

部分代码如下:

class LearnRunBase2 extends RunBase

{

    CustAccount         custAccount;

    CustInvoiceAccount  invoiceAccount;

    QueryRun            queryRun;

    int                 counter;

    DialogField         dlgCustAccount;

    DialogField         dlgInvoiceAccount;

         //syslastvaluelist是需要保存的用户输入数据

    #DEFINE.SYSLASTVALUECURRENTVERSION(9)

    #LOCALMACRO.SYSLASTVALUELIST

        custAccount,

        counter

    #ENDMACRO

 

    #DEFINE.SYSLASTVALUESFORKEDFROMVERSION(10)

         //Mycurrentlist是用来实现序列化的变量,是类中所有声明了的变量

    #DEFINE.MYCURRENTVERSION(11)

    #DEFINE.VERSION1(11)

    #LOCALMACRO.MYCURRENTLIST

        custAccount,

        invoiceAccount,

        counter

    #ENDMACRO

         //在为getLastsetLast定义专门的packunpack方法时,

//有可能改变原来mycurrentversion的值(如原来是10,现在被改为11),

//为了能够获取保存了的数据,将定义SYSLASTVALUESFORKEDFROMVERSION=10

    #DEFINE.VERSION1(10)

    #LOCALMACRO.CURRENTLISTV1

        custAccount,

        counter

    #ENDMACRO

}

 

public container packSysLastValue()

{

         //想把queryRun的值也保存起来

    return [#SYSLASTVALUECURRENTVERSION,#SYSLASTVALUELIST,queryRun.pack()];

}

 

public boolean unpackSysLastValue(container _packedValue)

{

    Version version = RunBase::getVersion(_packedValue);

    container packedQueryRun;

    boolean ret = true;

    ;

 

    switch (version)

    {

        case #SYSLASTVALUECURRENTVERSION:

        {

            [version,#SYSLASTVALUELIST,packedQueryRun] = _packedValue;

            if (SysQuery::isPackedOk(packedQueryRun))

            {

                queryRun = new QueryRun(packedQueryRun);

            }

            break;

        }

        case #SYSLASTVALUESFORKEDFROMVERSION:

        {       

                            //在原来的packunpack方法中,queryRun也被pack了起来

            [version,#CURRENTLISTV1,packedQueryRun] = _packedValue;

            if (SysQuery::isPackedOk(packedQueryRun))

            {

                queryRun = new QueryRun(packedQueryRun);

            }

            break;

        }

        default:

            ret = false;

    }

    return ret;

}

 

public void getLast()

{

    container packedValues;

    boolean         initParm = true;

    ;

         //不调用super(),先设置系统的一些标志

    getLastCalled   = true;

    inGetSaveLast   = true;

         //自定义获取值

    packedValues = xSysLastValue::getValue( this.lastValueDataAreaId(),

                                            this.lastValueUserId(),

                                            this.lastValueType(),

                                            this.lastValueElementName(),

                                            this.lastValueDesignName());

    //如果取到了值,判断是否可以unpack,如果没有,则使用默认赋值函数

if (packedValues)

        initParm = ! this.unpackSysLastValue(packedValues);

    if (initParm)

        this.initParmDefault();

    inGetSaveLast = false;

}

 

public void saveLast()

{

    ;

//不调用super()

    inGetSaveLast               = true;

    xSysLastValue::putValue(this.packSysLastValue(),//保存自定义的值

                            this.lastValueDataAreaId(),

                            this.lastValueUserId(),

                            this.lastValueType(),

                            this.lastValueElementName(),

                            this.lastValueDesignName());

    inGetSaveLast               = false;

}

 

 

 

原创粉丝点击