我以前的痛苦,你也拥有吗?
记得笔者在以前使用Delphi/C++/Java开发软件时,经常需要撰写许多的输入验证码,例如当用户输入身份证号,或是输入数值时,都需要根据企业逻辑来检查用户输入的数据是否正确,通常许多的验证逻辑程序代码几乎都是一样的,但是对于不同的程序语言,不同的开发环境都可能需要不断重写。更麻烦的是,由于一个团队拥有许多的开发人员,因此不同的开发人员可能会使用不同的程序代码,不同的验证逻辑,并且分散在整个应用程序不同的地方进行数据验证的工作。这造成了许多的困扰,例如当验证逻辑需要修改或是更正时,可能忘记改某些地方,或是由于开发人员撰写的方式不同,而让一些臭虫因此而出现。虽然后来许多的开发人员把这些验证程序代码封装成函式库统一让开发人员使用,或是封装成组件让开发人员使用,例如现在.NET/Java都提供了一些简单,常用的Validation组件,但是验证程序代码分散在整个应用程序不同的地方的问题仍然无法得到解决,而由这个现象延伸出的问题也一样存在。那么我们有什么好方法可以解决吗?
在回答之前也许我们应该想想这些验证程序代码的目的到底是什么?在这些验证程序代码中除了一般检查用户输入的字符,格式,长度或是语意之外,最重要的验证工作应该是用户的输入应该符合应用程序的企业逻辑规则,不是吗?
因此如果我们能够把这些验证程序代码进行的工作定义在企业逻辑模型之中,那么不管日后开发人员使用什么程序语言,或是在应用程序的什么地方,开发人员只需要在需要进行验证程序代码的工作时从企业逻辑模型中最出定义好的验证逻辑,再根据这些验证逻辑来验证用户输入的数据。如此一来一旦验证逻辑有改变或是更新,我们只需要更新定义在企业逻辑模型之中的验证逻辑,那么由于整个应用程序都是从企业逻辑模型中取得验证逻辑,那么我们不就解决了可能忘记更改一些分散在不同地方的问题了吗? 更进一步的想想,如果我们能够使用一段通用的程序代码来检查企业逻辑规则,而不需要对每一个不同的用户输入撰写不同的程序代码来检查,那么不是更棒吗(如果读者真的开发过这样的应用程序验证逻辑,就知道笔者说的痛苦,以及难以维护的程序代码了)?
问题是,能够有方法解决这长久以来的痛苦吗?
也许有可能,让我们继续往下看。
在UML中,开发人员可以使用OCL来定义类别/属性的验证逻辑或是约束条件,之后开发人员便可以在程序代码中藉由EcoSpace取得这些约束条件(Constraints),并且使用来验证异动的对象是否符合这些约束条件,一旦符合约束条件才能够更新回数据来源之中。在ECO架框中支持了这样的机制,ECO藉由提供开发人员使用OCL为ECO类别/ECO属性定义约束条件,以及在ECO架框中提供服务让开发人员能够在程序代码中存取这些约束条件并且执行约束条件以便验证对象。
在您了解了上面讨论的观念之后,接下来的内容中将深入的说明如何在企业逻辑模型中使用OCL来定义约束条件,并且使用来验证对象。
在企业逻辑模型中定义约束条件
开发人员可以在ECO的类别设计家中藉由对象检视器设定类别或是属性的Constraints特性来定义约束条件。使用Constraints特性定义约束条件时开发人员必须了解下面的观念:
l Constraints特性可以定义任何数目的约束条件
l 约束条件是使用OCL来撰写的
l 开发人员使用Constraints特性定义约束条件后,如果用户违反了约束条件那么仍然可以更新对象回数据来源。因此检查对象是否违反约束条件是开发人员的责任,开发人员必须确定对象在更新回数据来源之前没有违反约束条件。
现在让我们以图1的范例模型来说明如何定义约束条件以及如何在程序代码中检查企业逻辑模型的约束条件。
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><span lang="EN-US" style="FONT-SIZE: 9.5pt; COLOR: #404040; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><span lang="EN-US" style="FONT-SIZE: 9.5pt; COLOR: #404040; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><img height="353" alt="" width="409" src="http://tkfiles.storage.msn.com/x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBfHq8uRwTIDmA4mifa3QmX5Vqk3d9LBD5AmkfEdvlQ_vmycFoI-WZO0VTa3h81aJrwTsAr0b04asOfa0lICxuJzq7gRaHlVHAbPky3m3lJl1g"><span lang="EN-US" style="FONT-SIZE: 9.5pt; COLOR: #404040; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-fareast-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"></shapetype></span></shapetype></span></shapetype></span></shapetype>
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 306pt; HEIGHT: 264pt" alt="" type="#_x0000_t75"><imagedata o:href="http://tkfiles.storage.msn.com/x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBfHq8uRwTIDmA4mifa3QmX5Vqk3d9LBD5AmkfEdvlQ_vmycFoI-WZO0VTa3h81aJrwTsAr0b04asOfa0lICxuJzq7gRaHlVHAbPky3m3lJl1g" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.jpg"></imagedata></shape>
图1 范例模型
如下图所示,我们可以点选Joiner类别,并且在对象检视器中定义Constraints特性:
<shape id="_x0000_i1026" style="WIDTH: 264pt; HEIGHT: 210pt" alt="" type="#_x0000_t75"><imagedata o:href="http://tkfiles.storage.msn.com/x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBcVmcpmE8G1ocSXxCrdxOIgM10ReqId894DdhrbXRye-wi_QEugjuxvERz3VmOt-VstItlYOqdkOq63qQbf3h5a-EPwHkZLkL54SONjr0wBoQ" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image003.jpg"></imagedata></shape>
图2 在ECO设计家中为类别/属性定义约束条件
开发人员可以直接在Constraints特性中输入OCL或是点选Constraints特性旁的按钮启动Constraints编辑器,点选Constraints编辑器下方的Add按钮加入约束条件。下面的图形加入了两个约束条件,每一个约束条件必须输入约束条件的名称以及约束条件的OCL叙述,例如NameNotEmpty约束条件规定了Name属性不可为空白,同样的EMailNotEmpty也是类似的规定。
<shape id="_x0000_i1027" style="WIDTH: 356.25pt; HEIGHT: 83.25pt" alt="" type="#_x0000_t75"><imagedata o:href="http://tkfiles.storage.msn.com/x1phiCZJPhsUYg-Rf0H_plhOdSXMk_dnDiM8qsV6ywc6F3uYxTRe7HMJ8Sh9G06WJyiQC2iW1f7Lwwv3MtUUyP8Y01CFaHJfxWzdFWSM5APnoPRBgsJn4sMBA6PBcmK3W9T6T2YSwtuUb8" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image005.jpg"></imagedata></shape>
<shape id="_x0000_i1028" style="WIDTH: 414.75pt; HEIGHT: 73.5pt" alt="" type="#_x0000_t75"><imagedata o:href="http://tkfiles.storage.msn.com/x1phiCZJPhsUYg-Rf0H_plhOXYx_TAvJCyDG5gK2PJO_jGTuy7xyW7IXHSyhIqqH2I0VrFXdSzW1ZDRqlwtZRjjvTnNtl0MWzzozJbepZamh8SB_tIgaJ6I8XUeGfwaa32U5SDJI4-IeSo" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image007.jpg"></imagedata></shape>
图3 启动约束条件编辑器为Joiner类别定义约束条件
最后,范例企业逻辑模型也为DevCoSeminar的MaxCount属性定义了最多参加人数的约束条件必须小于120人:
<shape id="_x0000_i1029" style="WIDTH: 381pt; HEIGHT: 79.5pt" alt="" type="#_x0000_t75"><imagedata o:href="http://tkfiles.storage.msn.com/x1phiCZJPhsUYg-Rf0H_plhOZTkr49tqFLWT4TwQIYW5p8UBpqQ_l0vTML9e19L2TZWnu2OuMMDSitaiJ51KAx-veP9Nz4UwsU5WfpnMusLVdMAmglbr7-UDqY3NWC3B_VWGht4Qcoz_NI" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image009.jpg"></imagedata></shape>
图4 启动约束条件编辑器为DevCoSeminar类别定义约束条件
定义完Constraints的约束条件后,让我们再解释一下封装约束条件的IConstraint界面。
IConstraint界面
在ECO架框中企业逻辑模型中的约束条件是由IConstraint接口封装,定义的,开发人员藉由ECO架框服务接口存取到IConstraint接口,再藉由执行IConstraint接口定义的约束条件来验证对象是否符合企业逻辑。下面是IConstraint接口的定义:
public interface IConstraint: IModelElement
{
IExpression Body { get; }
IEcoConstraint EcoConstraint { get; }
}
IConstraint接口有两个只读属性,其中的Body即代表封装的约束条件,而EcoConstraint则是专属于ECO的额外信息。Body属性型态是IExpression接口,而IExpression接口的定义如下:
public interface IExpression
{
string Language { get; }
string Body { get; }
}
IExpression接口也有两个只读属性,其中的Language属性会回传约束条件使用的语言,通常都是”OCL”,代表是由OCL撰写的约束条件。而Body属性则是约束条件本身。例如前面的“NameNotEmpty”约束条件,它的IConstraint.Body.Body属性便是self.Name.Length>0。
IEcoConstraint接口也定义了两个只读属性,IsAutoGenerated属性回传这个约束条件是否是自动产生的,而Description则是约束条件的叙述文字:
public interface IEcoConstraint
{
bool IsAutoGenerated { get; }
string Description { get; }
}
因此在ECO程序代码中,要根据约束条件来验证对象,它的执行步骤如下:
l 从ECO企业逻辑对象中取得所有的约束条件的IConstraint接口对象
l 一一的使用IOclService执行这些约束条件并且判断约束条件是否符合
l 如果ECO企业逻辑对象符合约束条件才能够更新回数据来源
l 如果ECO企业逻辑对象不符合约束条件,那么就通知用户进行后续的处理
了解了IConstraint界面以及处理约束条件的步骤之后,接下来我们就可以使用范例和程序代码来展示如何使用约束条件了。
在程序代码中验证对象的约束条件
要如何使用程序代码来检查定义在企业逻辑模型中的约束条件呢? 其实非常的简单的,本书在第4章已经介绍了ECO的企业逻辑模型的静态通用机制,因此我们可以使用下面的步骤来完成检查企业逻辑模型中的约束条件:
l 在更新异动对象回数据来源之前,藉由使用IDirtyListService服务界面取得用户所有异动的对象
l 藉由ECO的企业逻辑模型的静态通用机制取得定义在企业逻辑模型中的约束条件
l 藉由IOclService服务接口一一的执行约束条件并且检查是否违反约束条件
l 如果没有违反任何的约束条件就更新对象回数据来源中
l 如果违反约束条件的话,保留违反约束条件的对象,要求用户进一步的处理
了解了进行约束条件检查的步骤之后,让我们看一些实际的程序代码来验证上面的步骤。
在下面的片段程序代码中是准备呼叫EcoSpace的UpdateDatabase方法把用户异动的对象更新回数据来源中,但是在这之前,它先呼叫了DoCheckObjectConstraints方法以便确定所有异动的对象是符合企业逻辑模型中的约束条件,否则DoCheckObjectConstraints会产生一个例外错误。
001 procedure TWinForm.Button2_Click1(sender: System.Object; e: System.EventArgs);
002 begin
003 try
004 DoCheckObjectConstraints;
005 EcoSpace.UpdateDatabase;
006 except on E: Exception do
007 MessageBox.Show ('对象违反约束条件' + e.Message +'无法更新回数据库',
008 MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
009 end;
end;
在DoCheckObjectConstraints方法中先在007行取得IDirtyListService接口,接着进入010行的for循环一一的取出每一个异动的对象并且呼叫DoHandleDirtyObject来检查每一个异动对象的约束条件是否符合。
001 procedure TWinForm.DoCheckObjectConstraints;
002 var
003 dol : IDirtyListService;
004 Iobj : IObject;
005 begin
//藉由IdirtyListServices取得异动的对象
007 dol := EcoSpace.DirtyListService;
008 if (dol.HasDirtyObjects) then
009 begin
010 for Iobj in dol.AllDirtyObjects do
011 begin
012 DoHandleDirtyObject(Iobj);
013 end;
014 end;
015 end;
最后的DoHandleDirtyObject方法在008行取得IOclService接口,在009行进入for循环,藉由IObject界面的UmlType.Constraints取得定义在这个对象类别中的所有约束条件,接着在012行呼叫IOclService的Evaluate方法来执行/评量约束条件。如果有任何对象违反了任何的约束条件就产生一个例外错误。
001 procedure TWinForm.DoHandleDirtyObject(Iobj : IObject);
002 var
003 IOcl : IOclService;
004 ICnt : IConstraint;
005 iCount: Integer;
006 bResult : boolean;
007 begin
008 IOcl := EcoSpace.OclService;
009 for iCount := 0 to Iobj.UmlType.Constraints.Count - 1 do
010 begin
011 ICnt := Iobj.UmlType.Constraints.Item[iCount];
012 bResult := boolean(IOcl.Evaluate(Iobj as IElement,iCnt.Body.Body).AsObject);
013 if (not bResult) then
014 raise Exception.Create(ICnt.Name);
015 end;
016 end;
现在如果我们执行上面的范例程序代码并且搭配图3和图4定义的约束条件,那么我们可以看到当执行下面的范例程序并且在DevCoSeminar对象的MaxCount属性中输入超过120的数值:
<shape id="_x0000_i1038" style="WIDTH: 272.25pt; HEIGHT: 221.25pt" alt="" type="#_x0000_t75"><imagedata o:href="http://tkfiles.storage.msn.com/x1phiCZJPhsUYg-Rf0H_plhOSWtknxeiS2-QkdBqtyffwpJUWyAhXyFVz2eNUVx8s3g24KpB9nnE29cftJOC3JLjoIC3cRg4nV9OOTiBKiDmwr2T01m_PEr6-Q-4swXsM6Gnq3yJFuPrEc" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image011.jpg"></imagedata></shape>
图5 修改DevCoSeminar对象的MaxCount属性值
那么在更新对象回数据来源之前就会看到下面的例外错误,代表上面的程序代码果然检查出了对象违反了约束条件。
<shape id="_x0000_i1039" style="WIDTH: 242.25pt; HEIGHT: 81.75pt" alt="" type="#_x0000_t75"><imagedata o:href="http://tkfiles.storage.msn.com/x1phiCZJPhsUYg-Rf0H_plhOWCKcfJtNVpJLY0ypd5yudKcNWSZxcPMjpGybfXzE2jNT2AwvHcgYOAe0SJd8xpumQO8swuWg8wa_6xlK8NI-I2vzdjTfLQodMwWhbwXDzagLvAwc964i1s" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image013.jpg"></imagedata></shape>
图6 程序代码检查出用户输入的数据违反了约束条件
如果我们接着又如下图对Joiner类别进行异动并且试着把EMail属性清为空白:
<shape id="_x0000_i1040" style="WIDTH: 296.25pt; HEIGHT: 222pt" alt="" type="#_x0000_t75"><imagedata o:href="http://tkfiles.storage.msn.com/x1phiCZJPhsUYg-Rf0H_plhOVxd_GP_XaUl1EruoaxcjOksXwxEk7f0J3KbAJVIhxfFtPOKzW3_gr1uNieA7Ip7BT7fbq8W1Zc8qvyu48h0GTfiNAJMiBruxb0vDT9UpVvg-ltczns48mo" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image015.jpg"></imagedata></shape>
图7 程序代码检查出用户输入的数据违反了约束条件
那么在更新对象回数据来源之前我们又可以看到范例程序检查出Joiner对象违反了EmailNotEmpty的约束条件。
从上面的程序代码看到了什么? 如果您有注意的话会发现只需要使用相同的一份程序代码,在一个程序/函式中就可以检查任何对象的任何约束条件。这和以前许多开发人员需要使用不同的程序代码,在不同的地方检查不同的用户输入资料是完全不一样的,这可以让程序代码更容易维护,也不容易产生臭虫,或是因为疏失而造成的错误。
如果我们进一步的结合.NET/开发工具提供的Validation组件和约束条件,那么我相信大多数的程序代码验证工作都可以顺利,有效率的完成。
您注意到,感觉到了使用模型和约束条件的好处了吗?
分享到:
相关推荐
同时,Anna教授也表⽰即便⾃⼰拥有再多的理论和经验,也还是和我们普通⽗母⼀样,每天在 提醒孩⼦们愉悦和痛苦的平衡,多巴胺短缺的状态和⼿机上瘾的风险。 这种⽆处可逃的社交媒体也让⼤多数⼈变得更在意别⼈的...
发环境(并不一定是最友好的,但一定是最强大的),我建议你一定要好好的熟悉一下 Linux。 三.如何得到Linux? 据我所知,大多数的 Linux 发行版本(Linux distribution)和核心(Kernel)都是可以 从网上下载...
我觉得这样做未免有些太霸道了,如果你说这叫偏执狂我也不反对,虽然我是狮子座,可也不想被人这样看。 在C#刚刚推出的时候,大多数的程序员都不免吼上两句——不是因为高兴,而是因为又多了一种语言。他们觉得现在...
电影中,爷爷的话“有些人浅薄,有些人金玉其外败絮其中,但总有一天,你会遇到一个绚丽的人,她让你觉得以前遇到过的所有人都只是浮云”成为了布莱斯自我觉醒的关键,也启示了观众对于真正品质的理解。 朱莉的善良...
我们都看过《谁动了我的奶酪》,这个非常简单的寓言故事就告诉我们,我们拥有的奶酪其实是在不断变化的,也就是我们在社会上所握有的筹码是不断变化的,不更新就会被用完,不注意保存就会变质。所以这提醒着我们随时...
5. 我们都看过《谁动了我的奶酪》,这个非常简单的寓言故事就告诉我们,我们拥有的奶酪其实是在不断变化的,也就是我们在社会上所握有的筹码是不断变化的,不更新就会被用完,不注意保存就会变质。 6. 在今后的生活...
- 示例:*I am able to do this.*(我能够做到这一点)。 5. **abnormal** (adjective): 不正常的,异常的。 - 示例:*His behavior is abnormal.*(他的行为不正常)。 6. **aboard** (adverb): 在船上,在飞机...
用C/C++手工别写一个存根例程是个十分痛苦的差使,尤其当远程方法的参数中包含特定的数据结构(如:记录、数组 、图等)时。幸运的是,gSOAP包中的'wsdl2h'WSDL解析器和'soapcpp2’存根及架构编译器能够将web服务...
随着AJAX迅速地引人注目起来,我想开发人员对这种技术的期待也迅速地增加。就像任何新技术,AJAX的兴旺也需要一整个开发工具/编程语言及相关技术系统来支撑。 1、JavaScript 如名字所示AJAX的概念中最...
克隆技术可能为更多不育夫妇提供生育的可能性,使他们有机会拥有自己的孩子,这在以前可能是无法实现的。通过克隆技术,未来可能会发展出更为有效且无痛苦的生育手段,极大地改善不育夫妇的生活质量。 【知识点三:...
对于拥有两台相机的用户,请转到Chrome的“设置”>“显示高级设置”>“隐私”>“内容设置”>“媒体”>“相机”。 ####说明1.单击Everest扩展图标开始跟踪2.随时按Ctrl + Shift + 3重新校准默认缩放...
2. **MySQL 5.5**: MySQL 是一个关系型数据库管理系统,也是开源软件,广泛用于 web 应用程序。在这个宿舍管理系统中,MySQL 5.5 存储所有关于学生、房间、床位、费用等的数据。其强大的查询功能和良好的性能使数据...