写点什么

使用面向.NET 的 Naked Objects 进行快速应用程序开发

  • 2009-04-14
  • 本文字数:3622 字

    阅读完需:约 12 分钟

面向.NET 的Naked Objects 作为一个框架,提供了针对.NET 框架下裸对象架构模式的 一种实现。裸对象背后隐藏的基本概念是在编写一个业务应用程序时,开发者只需要编写领域对象以及封装在领域对象中的业务逻辑。而该框架就会将领域对象以丰 富的面向对象样式的用户界面形式暴露给用户,同时还会处理这些对象的持久化与管理,这通常通过一个ORM 实现。对于那些提出领域驱动设计的人,这一模式可能正是投其所好。除了消除编写用户界面层和数据访问层的需求,裸对象模式还有助于良好的对象建模——因为你可以瞬间将一个原型领域模型转换为一个能够为业务用户评估的应用程序。

很多人听及此的第一反应就是它无法在大规模的复杂业务应用程序下工作。然而在爱尔兰政府的一个员工人数超过1000 人的部门 DSFA ,使用的应用程序就是 Naked Objects 开发的,它能够支持每年价值数亿欧元的社会保障金管理。

历史

Naked Objects 框架最初脱胎于 Java 平台。最早的版本是用 Java 1.1 编写的。在软件开发的历史长河中,一个最伟大的偶然事件是我们发现它能够未经修改就能够以 J#语言运行在.NET 平台上。然而,当 Naked Objects 的后期版本迁移到 Java 1.5 后,它与.NET 的兼容性就消失了。让人大吃一惊的是在 2007 年 1 月,微软证实从.NET 3.5 之后将不再支持 J#。

为解决这一问题,面向.NET 的 Naked Objects 就作为框架的完整重现应运而生。它使用 C#进行编写,设计时完全利用了.NET 平台的功能,包括泛型和 LINQ。而面向.NET 的 Naked Objects 创建的通用用户界面则使用 WPF 编写。

Naked Objects 的工作原理

通用用户界面并不依赖于代码生成:它是动态创建的。在运行时,框架使用了反射技术将领域对象呈现在用户界面上。这一技术被称之为“内省”技术,它支 持开发人员快速地将域模型转换为可用的应用程序。下面的截图展示了一个对象的打开视图,该对象包含了几个关联对象的链接(每个图标表示一个域对象);用户 可以通过单击浏览这些关联对象:

(文中所有的截图和代码示例都节选自一个简单的费用处理程序,该程序是 Naked Objects下载示例中的一部分。)

当然,很多能以简单的CRUD 用户界面形式呈现领域对象模型的框架都提供了数据库的浏览或维护功能。Naked Objects 之所以获得更多关注,则是它能够生成完整功能的应用程序。默认情况下,任何公共方法对于用户而言都是可用的,形式则是通过在对象图标上弹出 菜单的动作,而方法名则以动作名进行重新格式:

如果方法具有参数方法签名,通常会创建一个对话框用于调用动作,如:

<span color="#0000ff">public</span> <span color="#2b91af">IExpenseItem</span> CopyAnExistingExpenseItem( <span color="#2b91af">IExpenseItem</span> otherItem)则呈现为:

Other Item 字段要求用户拖动或粘贴一个类型为 IExpenseItem(UI 字段会拒绝其他任何类型的对象)的现有对象。在字段的右边同样是一个下拉框指示器,它能够自动提供一个列表对象,其类型在其他标签上对用户是可见的,这样就能够避免不必要的标签转换。

如果 Expense Item 在屏幕或下拉列表中不存在,用户如何能够找到它?或者说,当他们没有另外一个对象作为开始对象时,用户该如何创建一个新的对象实例?这正是仓储模 式和工厂模式所要解决的,它们都是领域驱动设计的标准模式。在 Naked Objects 的术语中,仓储和工厂都是服务样本,服务本身就是最上等的领域对象。服务的使用有三种方式。

第一种方式,服务提供主菜单,并呈现在屏幕顶端。通常这些菜单提供业务活动起点的动作,例如创建一个新的客户,或者查找一个现有客户。第二种方式,可以将服务注入到其他需要服务的领域对象中,这遵循了依赖注入(DI)模式。Naked Objects 以透明的方式管理服务的注入,你只需要为所需服务类型提供一个可设置的属性,而不需要像许多依赖注入框架所要求的那样在外部进行配置。

使用服务的第三种方式按照我们的术语规定就是“赠予动作”。如果服务具有一个公共方法:

复制代码
<span color="#0000ff">public</span> <span color="#0000ff">virtual</span> <span color="#2b91af">IList</span> <<span color="#2b91af">RecordedAction</span>>
allRecordedActions(<span color="#2b91af">IRecordedActionContext</span> context)

那么它就会自动作为一个用户动作被“赠予”给实现了IRecordedActionContext的任何对象,你所选择的动作所执行的对象会自动填充对话框的第一个字段。(该动作表现为“Recorded Actions”子菜单,如第一张截图所示——并成为提供该动作的服务名)。

Naked Objects 最强大的功能是为你提供了一种实现多继承的方法(至少从用户的角度来讲是如此)。它的某些概念与 mix-ins 或者.NET 扩展方法的概念相仿,虽然在实现上略有不同。

实现业务规则

你该如何实现业务规则呢?有两个选择。其一是使用特性,它可以应用到类、属性、方法或参数。例如:

  • 默认情况下,框架会要求用户能够在保存一个对象之前完成所有字段,并且能够在执行动作之前,在对话框中提供所有字段。你可以使用 [Optionally()] 特性重写该行为。
  • [MaxLength()],``[Mask()][RegEx()]允许你为输入字符串指定约束以及 / 或者对他们进行格式规范。
  • 如果因为编程的原因,你必须将属性或方法定义为public,但又不应暴露给用户,则可以使用[Hidden]。各种条件都可以应用到该特性上。
  • 默认情况下,类、属性和动作的名称都会被使用,在用户界面上可以对其名称进行合理的格式规范。我们认为这是一个好的实践。然而,如果你需要一个代码不会使用的 label(例如它包含了符号或标点),则可以使用[Named()]。(注意这是一种完全独立的机制,它为所有 label 提供了国际化支持)。

第二种选择更为灵活,可以根据下面所展示的约定采用编程方式:

复制代码
<span color="#0000ff">public virtual void</span> CopyFrom(<span color="#2b91af">IExpenseItem</span> otherItem) {...}
<span color="#0000ff">public virtual string</span> ValidateCopyFrom(<span color="#2b91af">IExpenseItem</span> otherItem) {...}

在本例中,CopyFrom方法会作为一个用户动作被框架所呈现;框架同时能够识别ValidateCopyFrom方法,作为验证动作参数的逻辑:如果方法返回一个非空字符串,则对话框的“OK”按钮就会从灰色转为可用,字符串消息则作为工具提示显示给用户。相似的,DisableCopyFrom可以使得动作不可用,譬如当一项主张已经被持久化。(注意,框架具有一套完全独立的基于用户角色管理许可的机制)。还有其它一些约定,例如指定默认值或者为参数指定选项(下拉列表)。

POCOs

这些编码约定增加了可选的行为。你必须遵守三种简单的编码约定。有两种是应用在属性上的,如下所示:

复制代码
<span color="#0000ff">public virtual</span> Employee Claimant {
<span color="#0000ff">get</span> {
Resolve(employee);
<span color="#0000ff">return</span> employee;
}
<span color="#0000ff">set</span> {
employee = <span color="#0000ff">value</span>;
ObjectChanged();
}
}

Resolve()调用确保对象已经被加载到内存中,而ObjectChanged()则会通知框架属性值已经改变。两者都是为了更新对象的视图,以及确保改变被持久化。(注意框架会为你自动化处理持久化:你不需要为加载、保存和更新对象编写任何方法)。

第三个要求是你编程创建的任何对象都必须通知框架。你不能这样写:

<span color="#0000ff">Employee</span> employee = new Employee();而需要这样:

<span color="#0000ff">Employee</span> employee = Container.NewTransientInstance< <span color="#2b91af">Employee</span>>();这些调用并不是 Naked Objects 框架要求的,而只是将其委托给定义在IDomainObjectContainer中的方法。如果你为你的对象类型提供了一个属性,框架就会将其注入到容器中,该容器在运行时为你实现这些功能。作为一种快捷方式,你可以选择让域对象继承自AbstractDomainObject,它可以代替你为每种情形生成这几行代码。

但是必须声明的重点是继承是可选的:Naked Objects 是一个基于 POCO(Plain Old CLR Object,普通旧式 CLR 对象)的方式。除了通常意义上 POCO 所具有的优势外,它还意味着你可以选择使用相同的域对象,并将其运行在更加广泛的架构中:编写必要的用户界面和其他层。你所需要做的就是为容器提供这三类调用的存根代码。(如果你希望使用面向方面编程,你可以从域代码中去除Resolve()ObjectChanged()newTransientInstance()调用,但是我们不希望将 Naked Objects 与具体的 AOP 实现紧密耦合。)

Naked Objects 引人入胜之处是你可以只使用它就能够支持开发过程中的领域驱动设计:Naked Objects 不会强迫你必须要实现整个系统。还有一个好消息是你可以只使用 Naked Objects 的表达式编辑器,它可以免费下载


给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2009-04-14 06:493540
用户头像

发布了 109 篇内容, 共 40.8 次阅读, 收获喜欢 14 次。

关注

评论

发布
暂无评论
发现更多内容

ElasticSearch 高级检索,按照顺序进行搜索

alexgaoyh

elasticsearch dsl 顺序搜索 高级检索 与或关系

【Linux】系统中安装Go环境

A-刘晨阳

Go Linux 三周年连更

打造安全无忧软件应用的十大最佳实践

龙智—DevSecOps解决方案

软件开发 软件开发安全

运维审计录像的作用是什么?用什么软件好?

行云管家

堡垒机 运维审计 审计录像

RocketMQ 多级存储设计与实现

阿里巴巴云原生

阿里云 RocketMQ 云原生

Databend v1.1 版本发布!

Databend

实战分享丨 MySQL 与 Django 版本匹配相关经验

Java你猿哥

Java MySQL SSM框架 实战 Diango

ReentrantLock和Synchronized使用与区别,多线程安全问题

共饮一杯无

synchronized ReentrantLock 三周年连更

云服务是什么意思?有什么用?

行云管家

云计算 云服务

人工智能会取代人类成为地球的主宰么?| 社区征文

毛小毛

人工智能 ChatGPT 三周年征文

阿里高工纯手写的《分布式架构手册》仅仅一天GitHub就标星128K

Java你猿哥

架构 分布式 分布式架构

Linux 修改系统时间的两种方式

会踢球的程序源

Java Linux

缓存一致性设计思路

我爱娃哈哈😍

redis 缓存 缓存一致性

解决流水线瓶颈、提升编码效率的五个方法(上篇)

龙智—DevSecOps解决方案

ci cicd 持续集成 流水线

爆肝一月!527页文档详解SpringCloud微服务和分布式系统实践

Java你猿哥

数据库 分布式 SSM框架 微服务设计

如何将一个链表分组并对每组进行反转?

Java你猿哥

Java 链表 架构师 SSM框架 链表结构

PostgreSQL技术内幕(七)索引扫描

酷克数据HashData

数据库 postgresql

互联网工程师Java面试八股文及答案整理(2023最新版)

Java你猿哥

Spring Cloud springboot java面试 面经 JVM面试

某程序员哀叹:写几年代码,回头一看80%都没用,没法写上简历!

Java你猿哥

Java 程序员 面试 简历

解析单存储库:定义、优势与挑战

龙智—DevSecOps解决方案

谷歌 Monorepo Monolith 单储存库

涅槃重生!字节大牛力荐大型分布式手册,凤凰架构让你浴火成神

Java你猿哥

架构 分布式架构 凤凰架构

Postman Runner 使用指南

Liam

Java 后端 Postman 接口测试 API 开发

【经验分享】硬件工程师需要知道的DFM可制造性设计

华秋PCB

工具 电路 PCB PCB设计 可制造性

OneCode 开源集成开发工具ESD功能介绍

codebee

开源 低代码平台

关于自托管环境,您了解多少?

龙智—DevSecOps解决方案

Atlassian Data Center

600+ 道 Java面试题及答案整理(建议收藏)

会踢球的程序源

Java 面试 java面试 应届生 Java八股文

如何解决spring的循环依赖问题?

做梦都在改BUG

Java spring 循环依赖

优秀的pdf编辑器:Acrobat Pro DC 中文直装版

真大的脸盆

Mac PDF Mac 软件 PDF格式转换

分布式文件系统FastDFS

会踢球的程序源

Java fastdfs 分布系统

研究思考丨关于软件复杂度的困局

阿里巴巴云原生

阿里云 云原生 复杂度

大咖力荐 |《中国企业软件研发管理白皮书》为什么值得看?

万事ONES

使用面向.NET的Naked Objects进行快速应用程序开发_.NET_Richard Pawson_InfoQ精选文章