【ArchSummit】如何通过AIOps推动可量化的业务价值增长和效率提升?>>> 了解详情
写点什么

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

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

关注

评论

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

【量化】股市技术分析利器之TA-Lib(二)

恒生LIGHT云社区

量化投资 量化

ZEGO 即构科技首发适配鸿蒙系统的 Express SDK 1.0 版本,并正式启动公测!(内附源码)

ZEGO即构

音视频 HarmonyOS 鸿蒙开发 即构科技

对象存储手把手教七 | 存储空间授权策略 Bucket Policy

QingStor分布式存储

分布式系统 对象存储 分布式存储 分布式,

Flink 是如何统一批流引擎的

编程江湖

大数据 flink

实战篇:断点续传?文件秒传?手撸大文件上传

阿Q说代码

断点续传 签约计划第二季 文件秒传 文件分块 文件合并

如果还不懂如何使用 Consumer 接口,来公司我当面给你讲!

阿Q说代码

函数式接口 签约计划第二季 consumer 实战讲解 supplier

【量化】股市技术分析利器之TA-Lib(一)

恒生LIGHT云社区

量化投资 量化

博文推荐|使用 Pulsar IO 打造流数据管道

Apache Pulsar

Java 开源 架构 云原生 Apache Pulsar

如何设置Activity背景颜色与ProgressBar进度条颜色

Changing Lin

12月日更

实战篇:Security+JWT组合拳 | 附源码

阿Q说代码

spring security JWT 签约计划第二季 权限验证

PackML从会到不会——标签(3)

陈的错题集

标准化 PackML

看了同事写的代码,我竟然开始默默的模仿了。。。

阿Q说代码

策略模式 多态 签约计划第二季 自定义参数解析器 统一验签

语法糖甜不甜?巧用枚举实现“状态”转换限制

阿Q说代码

枚举 签约计划第二季 语法糖 订单状态转换

看了这么多年西游记,你可知道孙悟空是如何召唤土地公公的吗?

阿Q说代码

Java 观察者模式 签约计划第二季 事件通知机制

IoT Stack 2.0升级物模型及数据交互协议, 大幅提升物联网方案交付速度

百度大脑

人工智能 百度 物联网

用户登录设计之双token设计

CRMEB

WeTest小程序质量专项方案推出,小程序异常监控内测招募中

WeTest

「Spark从精通到重新入门(一)」Spark 中不可不知的动态优化

尔达Erda

云计算 大数据 spark 开发者 感悟

后端开发实战总结 | 签约计划第二季|后端

阿Q说代码

内容合集 签约计划第二季 技术专题合集

Flink CDC 系列 - 构建 MySQL 和 Postgres 上的 Streaming ETL

Apache Flink

大数据 flink 编程 后端 实时计算

【活动报名】Apache ShardingSphere Dev Meetup 重启!

SphereEx

开源项目 开源社区 ShardingSphere Meetup SphereEx

Linux学习方法《Linux一学就会》Linux系统进程管理

侠盗安全

Linux linux运维 运维工程师 云计算架构师

恒源云(GPUSHARE)_GPU白嫖大法来袭!

恒源云

深度学习 gpu 算力加速

Spark从入门到精通

冇先生

长连接网关技术专题(六):石墨文档单机50万WebSocket长连接架构实践

JackJiang

websocket 即时通讯 IM 网关

还在用BeanUtils拷贝对象?MapStruct才是王者!【附源码】

阿Q说代码

Java MapStruct 签约计划第二季 深拷贝与浅拷贝

高校企业双向赋能,首届飞桨启航菁英计划圆满结束

百度大脑

人工智能 百度 飞桨

科技热点周刊|PHP 基金会成立、Rust 内讧、Amazon Linux 2022 预览版发布

青云技术社区

云计算

大数据中不同文件格式的比较

DisonTangor

大数据 云存储

『上线』OpenSEC SIGs 终于成立了!

SphereEx

开源社区 ShardingSphere SphereEx 中文开源 OpenSEC

秒过!度目智慧通行让常态化防疫更高效

百度大脑

人工智能 人脸识别

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