Naked Objects是一种架构模式,也是一个以领域对象为中心角色的应用开发框架。Naked Object应用中的领域对象是用户界面的核心,同时也是开发活动的焦点。Naked Objects最近发布了3.0版,它支持Java 1.5、注入(injection)、一个可选UI、Hibernate对象存储、集成安全和认担动作(Contributed Actions)。其间他们与爱尔兰社会和家庭事务部门一道进行的努力,为使用Naked Objects提供了一个有价值的学习案例。
InfoQ借机与Naked Objects集团的共同创办人、Naked Objects模式的创造者Richard Pawson进行了沟通。
Naked Objects模式鼓励开发者关注于设计带有数据和行为的富领域模型,而它则自动提供一个展现层和一个瘦控制层。
Naked objects源于对下面这一个有效循环的认识:
如果你决心设计有完善行为的领域对象,那么为用户展现领域对象的直观视图和存取方法,就是用户界面要做的全部——而这些都可以由反射机制来自动完成。如果你把用户界面设计成领域对象的直接反映,那么用户界面将强迫,同时也帮助你完善领域对象的行为。
这种着眼于领域模型的方法与领域驱动设计有着相似之处:
我想他们是非常互补的。现在大家称为DDD(领域驱动设计,即Domain-Driven Design)的理念驱使我在90年代后期开始构想Naked Objects,我们在Naked Objects中应用了这些模式。
首先,我真认为所有坚信DDD思想的人都应该使用Naked Objects,因为它让DDD的好处更加具体和明显,它也让DDD的过程更容易满足业务。多年的经验让我发现,讨论UML图表不能吸引商业赞助人,这也是人们为什么通过屏幕线框图来设计系统的原因(一个很不好的主意)——因为它很容易吸引人们对屏幕布局进行讨论。用Naked Objects构建你的领域模型原型会更容易满足业务要求,因为业务实际上关注的就是领域模型本身。
其次,我相信Naked Objects和DDD会互相促进,因为它避免了在手工开发上层的展现层和控制层时,抵消掉领域模型的力量的问题,我最近的Blog就是关于这一主题的。
就Naked Objects是如何帮助你探索领域展开来谈:
随着我们越来越多地使用Naked Objects,我们学到的一个普遍性质就是,UI会强迫你将一些否则可能会忽略的东西放入领域模型。模型也因此更全面地表现了现实——模型绝不会不恰当或不优雅。Naked Objects的方法还为业务本身澄清了概念。我最喜欢的例子就是“预付款”和“后付款”,这在最初的标书里就有描述,通俗讲它的意义就是:一个还没有付款,而另一个已经完成付款。
但我们要问的问题是:预付款是怎么来的?得到的答案是那是用户的权益(如最后他们可以获得养老金)。实际上,我们可以把“预付款”改成“权益金(Entitlement)”,而“后付款”就对应变成“支付款项(Payment)”。权益金是预先计算的(可以回溯调整),当权益金到期时,就用“支付款项”去清偿“权益金”。
当然,Naked Objects不可能适合所有的应用,Richard特别警告那些面向消费者的应用:
使用Naked Objects开发交付的应用只适合于内部用户,而不是公共访问型应用。 我们从来没有声明过生成的用户界面很“直观”——实际上,研究说明不存在什么直观的用户界面,只有熟悉的用户界面——其中肯定会存在学习曲线的问题,但我们交付界面的目标总是把用户“看做问题解决者,而不仅仅是流程跟随者”。
Naked Objects 3.0支持直接在领域类中添加Java1.5标注来实现声明式的数据验证和字段排序,向领域模型注入共享的服务,HTML和富客户端界面(还会有更多,如Eclipse RCP、命令行和AJAX),集成Hibernate以支持领域模型的存储,一个内建的安全模型(它能在数据库、简单文件或LDAP中进行存储和管理),认担动作。Naked Objects 3.0还改用了Apache许可。
认担动作(contributed actions )允许服务将动作贡献到领域模型,并成为用户界面的一部分。不过这样做的风险是错误地鼓励了开发者将行为从领域类转移到服务层:
我们最近为一位大客户完成了一个短期项目,当时客户声称项目已经按照SOA的规则进行了架构设计(但没有实现),他们把所有的行为都放在了服务层。于是我们使用Naked object非常快速地为他们的模型构建了一个原型,原型中定义了完全贫血的实体,并让服务承担所有的动作。我们绝对不推荐这样进行设计,但当时的问题是要么在他们已完成部分上继续工作,要么就不做。不过,结果我们得以通过这样的设计向他们说明他们对服务的观念是很贫乏的,而且极度不协调。当然,我们也说明了如果他们当初尽量将行为放进领域对象,结果会更加好。
我们的观点是,仅当需要在不同对象间实现同一个行为而又无法使用继承时,才使用认担动作。这是绕过单一继承限制的一个有效途径。认担动作很像AOP,只不过它是发生在运行时,而不是编译时。
也可以结合使用AOP和Naked Objects,Naked Objects的Blog上已经演示过。从GPL许可换成Apache许可是为了回应用户的要求:
不幸的是,有相当多的人不愿意与GPL产品打交道,同样,在保证与Naked Objects使用的各种开源库的许可兼容的问题上,GPL给我们带来了一些麻烦。
关于Naked Objects接受程度的问题:
我们发布Naked Object 3.0获得了良好的反响(第一周就有超千次下载)——我们认为这是Naked Objects第一个比较完善的实现。我们的新版本发布通知邮件列表里 有几百人进行了登记。但是抛开DSFA项目这个意外惊喜不谈,我不得不承认它毕竟还是一个刚刚成长起来的技术,大多数人仍然会将它作为一个原型工具,而不是一个完整的部署平台。我们期待在接下来的几个月里,它会获得实质的成长。
我强烈感受到其它许多技术正越来越接近Naked Object的理念(Ruby on Rails、Spring ROO等),我们朝我们看到的这些趋势的理想终点笔直前进。因此,Naked Objects相比主流开发而言,常被视为太激进(或者叫做固执)。或许这样说没错,但我们已经见识过它的力量,因此我们决不会回头。
Richard Pawson在他的Blog上详细对比了Naked Object和Ruby on Rails以及Grails。
爱尔兰社会及家庭事务部(DSFA)是Naked Objects最著名的样板。DSFA与Naked Objects的第一个试验项目是2002年启动的,在2004年再次与Naked Objects集团续约,到2007年9月该应用已经“持续被超过700用户使用”。而且:
2007年5月,DSFA宣布一个新的四年计划,进一步扩展新的架构,开发一系列全新的应用,同时将更多遗留的系统移植到新的平台上来。希望可以在项目期间通过Naked Objects将用户数提高到数千。
然Richard Pawson不愿对进行中的架构扩展进行评论,但他保证将会有更多新东西。下一步会有:
可选自动生成用户界面、一个全新的自动化测试框架、开发工具,但我可不想提前公布。
对DSFA项目的案例研究得出了这些优点:敏捷性、原型化和重用。
就代码重用主题来讲:
查看英文原文: Naked Objects adds Java 1.5, Injection, Hibernate这么说有两个原因:第一个很简单,那就是Naked Objects鼓励好的对象建模(行为丰富的实体,大量的多态),而对象建模就是为了更好的重用;第二个原因就是在Naked Objects环境里 ,当你在应用间重用领域对象时,不必担心UI的问题。在传统架构中,如果你想重用,如重用一个“Customer”对象,你要么必须编写新的视图和控制器,要么重用前一个应用中的视图和控制器,结果却发现这些视图和控制器并不仅仅与“Customer”对象相关联,不得不大动干戈。
这里面还有一个政治因素。以我的经验看来,如果你想让一个房间内所有的利益相关方都对Customer对象有一个共同的定义,只有一个结果,不可能——他们不可能被说服,因为他们每一个人都有不一样的需求。但是,如果你能展示些什么让他们知道你正在做他们每个人想要的,那就简单了。Naked Objects项目的成功之处就在于可以向不同的利益相关方展示(不仅仅是告诉他们)同一个业务对象模型是如何满足他们各自的需要,而传统的UML建模就做不到这一点的。