第一种方式,服务提供主菜单,并呈现在屏幕顶端。通常这些菜单提供业务活动起点的动作,例如创建一个新的客户,或者查找一个现有客户。第二种方式,可以将服务注入到其他需要服务的领域对象中,这遵循了依赖注入(DI)模式。Naked Objects以透明的方式管理服务的注入,你只需要为所需服务类型提供一个可设置的属性,而不需要像许多依赖注入框架所要求的那样在外部进行配置。
使用服务的第三种方式按照我们的术语规定就是“赠予动作”。如果服务具有一个公共方法:
allRecordedActions(IRecordedActionContext context)
那么它就会自动作为一个用户动作被“赠予”给实现了IRecordedActionContext的任何对象,你所选择的动作所执行的对象会自动填充对话框的第一个字段。(该动作表现为“Recorded Actions”子菜单,如第一张截图所示——并成为提供该动作的服务名)。
Naked Objects最强大的功能是为你提供了一种实现多继承的方法(至少从用户的角度来讲是如此)。它的某些概念与mix-ins或者.NET扩展方法的概念相仿,虽然在实现上略有不同。
实现业务规则
你该如何实现业务规则呢?有两个选择。其一是使用特性,它可以应用到类、属性、方法或参数。例如:
默认情况下,框架会要求用户能够在保存一个对象之前完成所有字段,并且能够在执行动作之前,在对话框中提供所有字段。你可以使用[Optionally()]特性重写该行为。
[MaxLength()], [Mask()]和[RegEx()]允许你为输入字符串指定约束以及/或者对他们进行格式规范。
如果因为编程的原因,你必须将属性或方法定义为public,但又不应暴露给用户,则可以使用[Hidden]。各种条件都可以应用到该特性上。
默认情况下,类、属性和动作的名称都会被使用,在用户界面上可以对其名称进行合理的格式规范。我们认为这是一个好的实践。然而,如果你需要一个代码不会使用的label(例如它包含了符号或标点),则可以使用[Named()]。(注意这是一种完全独立的机制,它为所有label提供了国际化支持)。
第二种选择更为灵活,可以根据下面所展示的约定采用编程方式:
public virtual string ValidateCopyFrom(IExpenseItem otherItem) {...}
在本例中,CopyFrom方法会作为一个用户动作被框架所呈现;框架同时能够识别ValidateCopyFrom方法,作为验证动作参数的逻辑:如果方法返回一个非空字符串,则对话框的“OK”按钮就会从灰色转为可用,字符串消息则作为工具提示显示给用户。相似的,DisableCopyFrom可以使得动作不可用,譬如当一项主张已经被持久化。(注意,框架具有一套完全独立的基于用户角色管理许可的机制)。还有其它一些约定,例如指定默认值或者为参数指定选项(下拉列表)。