写点什么

使用面向.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:493572
用户头像

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

关注

评论

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

深度探讨全链路测试:定义、特点及与其他测试方法的对比

Apifox

测试 单元测试 自动化测试 全链路测试 测试工具

喜报!上海电力联合乘云数字获评 "中国信通院可观测性实践优秀案例"

乘云数字DataBuff

敏捷:应对软件定义汽车时代的开发模式变革

DevOps和数字孪生

软件定义汽车

每日一题:LeetCode-128. 最长连续序列

Geek_4z9ami

Go 面试 算法 数组 LeetCode

php设置和获取Cookie教程。

百度搜索:蓝易云

php Linux 运维 Cookie 云服务器

强大模型与高效工具的完美结合

百度开发者中心

深度学习 nlp 大模型

抢占式批任务分配设计

Windows 平台下如何安装与配置 MySQL 5.7.36

小魏写代码

淘宝店铺所有商品数据接口(Taobao.item_search_shop)

tbapi

淘宝API接口 淘宝店铺所有商品数据接口 淘宝商品数据接口 淘宝整站商品数据接口 淘宝店铺商品接口

如何使用凹凸贴图和位移贴图制作逼真的模型

3D建模设计

WebGL 3D渲染 three.js 材质编辑 材质纹理贴图

万字带你熟悉静态分析工具的评估测试

华为云开发者联盟

后端 软件开发 华为云 华为云开发者联盟

人工智能的局限性与期望管理:理解’人工智障’的瞬间

人工智能

java浅拷贝BeanUtils.copyProperties引发的RPC异常 | 京东物流技术团队

京东科技开发者

发布!乘云数字参编中国信通院《可观测性技术发展研究报告》正式发布

乘云数字DataBuff

QCN6224 VS QCN9274 What are the performance differences? - As an M.2 WiFi7 card chipset

wifi6-yiyi

如何思考软件工程师与AI的共存发展

Onegun

AI 工程师 AI编程

软件开发

Geek_8da502

OpenHarmony城市技术论坛武汉站:探索大模型时代的终端操作系统创新

科技热闻

探索在线教育流量从小程序中挖掘

Onegun

小程序 在线教育 在线学习

软件开发

Geek_8da502

Next Station of Flink CDC

Apache Flink

大数据 flink 实时计算

Mac电脑系统活动监控器推荐:iStat Menus最新中文版

胖墩儿不胖y

Mac软件 活动检测工具

Salesforce携手阿里云再来,这次本土CRM有几分胜算?

ToB行业头条

iCollections for mac(桌面整理软件) v8.1.81006永久激活版

mac

桌面管理工具 苹果mac Windows软件 iCollections

Miniconda安装使用教程

百度搜索:蓝易云

Python Linux 运维 云服务器 Miniconda

开卷有益,思想有力:华为阅读发布2023年度榜单

最新动态

精彩回顾|【ACDU 中国行·西安站】数据库主题交流活动成功举办!

墨天轮

数据库 postgresql opengauss oceanbase KaiwuDB

Skia 编译及踩坑实践

京东科技开发者

QCN6224 vs QCN9224 - as a WiFi7 card chip - What are the different performance?

wifi6-yiyi

QCN6224 QCN9224

华为、海信、TCL、CEC等龙头企业齐聚“2024深圳电子展会”

AIOTE智博会

电子展 深圳电子展 电子信息展 电博会

记一次kubernetes获取internal Ip错误流程

华为云开发者联盟

后端 开发 华为云 华为云开发者联盟

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