阿里云「飞天发布时刻」2024来啦!新产品、新特性、新能力、新方案,等你来探~ 了解详情
写点什么

用 Qi4j 进行面向组合编程

  • 2009-01-04
  • 本文字数:3655 字

    阅读完需:约 12 分钟

长期以来,通过 OOP 对象集对领域概念进行建模的目标并未得到充分实现。那么迄今为止,我们万般努力但难以解决的根本问题到底是什么?有没有更好的解决办法?在本文中我们将介绍面向组合编程(COP,Composite Oriented Programming)的概念,展示它如何规避 OOP 存在的一些问题,并重先点燃使用可重用部件组装领域建模的希望。

问题

我为何物?实际中我可以有多重身份。某些时候,我是编写软件的开发者;另些时候,我是给大家讲解某个有关 Java 话题的软件开发者。但其他时候,我可能有完全不同的身份,比如银行的客户、大学的校友。简而言之,我不同时候的身份,由当时的具体环境决定。在不同的环境中,我需要通过不同接口、以相应行为与之交互。在所有这些环境中,我其实就是具有不同接口同一个对象。在我编写软件的时候银行不会出现另一个我。

解决方案

如果在软件中用 OOP 为我建模,一些人会将我设计为一个 Developer 类。但这样一个类显然不能在不同时候表达我的不同身份(比如一个大学校友,因为 Developer 类不包括社交概念)。因此对我建模的结果,可能会是几个不同的类,或者在一个类中实现所有行为。在本文中,我们提出另一种方案:利用 Mixin(混入)概念完成这个实现。

组合

首先,Mixin 被实现为一个普通 Java 类,它通常实现一个特定接口,而这个接口将是 Composite 所要暴露接口的一部分。接着,我们用如下方法声明一个 Composite:创建一个 Java 接口,用注解声明它要用到的 Mixin,并且使用“extends”关键字指明需暴露哪些领域接口。通过这一方法,我们就可以载一个集中的地点明确定义 Composite 的结构和行为。

使用 COP 时,虽然把横切关注点保留在独立的实现类中是一个不错的主意,但是它们的装配或组成方式应该还是集中用 Java 接口来说明。为了避免出现重复的说明,我们可以通过“extends”关键字重用被扩展接口中的声明。这样,如果修改了被扩展接口,从其扩展而来的 Composite 接口声明就会自动改变,不需我们逐个做人工修改。

利用这种办法,我们相信可以做到两全其美:存在于各个单独实现类中的关注点实现了分离,每个类仅需关注特定的任务;对于 Composite 最终应该是什么样的描述则是集中和确定的,这样,Composite 的开发者就可以全权负责定义中应该包含的内容。

代码示例

Composite 在实际中如何具体应用呢?让我们看一个例子。假设我是一个 Composite,那么可如下描述我:

复制代码
@Mixins({DeveloperMixin.class, SpeakerMixin.class, AlumniMixin.class})
public interface HumanComposite
extends Developer, Speaker, Alumni, Composite
{}

被扩展接口中包含了实际要被调用的方法,由 Qi4j 运行时环境去构造一个 Composite 实例,这一实例可以将“来自客户端的调用”路由给特定的 Mixin 实例。但从客户端的角度看,这个 Composite 实例完全是一个普通 Java 对象(尽管与普通 OOP 方法实现的领域对象比较起来,它有更多的接口)。像 Developer 这样的领域接口是普通接口,和 Qi4j 无任何特殊关系,其实现本身也是实现了该接口的简单 Java 类。但是上面所说的领域对象的身份是由 Composite 实例而非某个 Mixin 实例定义的,这样就解决了身份问题:对“我”这个对象的引用,可在系统范围里传递,并被传递给在特定上下文环境中很有用的接口。如果引入更多领域或上下文环境时,也可通过扩展这个 Composite 来处理。

如需想创建另一个也使用 Alumni 接口的 Composite 及其实现,我们可以让此接口也扩展 Alumni,并声明使用相同的 Mixin。因此,多重继承和复用基础类的常见问题也解决了。

LMM 结构

软件通常是在纸上分模块、分层进行设计的。我们对类似如下的设计图已经非常熟悉了:

这个图包含有多个模块,不同模块构成了不同层,而各层又叠放在一起。我们可将这种设计方法简称为 LMM(Layered Modules Metaphor,分层模块表示法)。LMM 图可用来传达一个整体应用的总括,不让我们陷入太多的细节当中。严格按照 LMM 的要求设计系统,可减少系统缺陷、降低长期维护成本,这种系统对未来变更的反映也可更为灵活。绝大多数项目都使用 LMM 来描述应用程序的构成方式,许多项目设法遵循 LMM,但只有很少的项目是按此执行的。我想我们都已经看到过很多惨痛教训,比如在基础结构层的类中直接使用 Web 层的类。

Qi4j 支持的结构

Qi4j 目前已经能为 LMM 提供明确的支持,这有助于规范团队中开发人员的行为。Qi4j 应用结构是一个小规则集:

  • 结构

  • 所有结构在应用启动时静态声明

  • 所有 Composite 实例都有所属模块

  • 所有服务都有所属模块

  • 所有模块都有所属层

  • 所有层都有上下层次关系(但不循环)

  • 所有层一起构成了应用

  • 访问

  • 模块能访问同层的所有其他模块

  • 层能访问它的直接下级层(不能跃层访问)

  • 可见性

  • Composite 实例缺省只在所属模块内可见

  • Composite 实例也能设置为在层内或层间可见

看起来比较复杂,其实不然。本质上,Composite 实例在创建它们的模块中都是私有的,除非显式声明为对模块外或层外公开。这和在普通 Java 中使用“public”和“pirvate”修饰词限定类的可见性是类似的。

Qi4j 目前尚不提供其他可供选择的结构,但其包含了构造常用应用程序结构的简单方法(包括一个层中只包含一个模块的情况)。

结构的使用

领域代码无需了解应用程序结构,但可以用 @Structure 注解的形式出现。如下例所示:

CompositeBuilderFactory 将在创建时被注入 Mixin,而且它仅允许代码实例化结构中可见的 Composite。

结构发挥作用的另一个常见例子发生在查找服务时。若在相同模块中有且仅有一个要求类型的服务,那么就无需引入额外装配(Assembly)。服务的使用变得十分简单。

例如,如果服务 GenericInventory 被声明在 Bread 模块中,那么每个 inventory 服务实例都将受其邻近各自客户端的程度约束。

应用结构的生成

Qi4j 应用需通过应用程序代码实现自举,最简单的启动方法大致如下:

另外,还可利用 SingletonAssembler 编写上述功能:

SingletonAssembler 是一个用于创建单层单模块 Qi4j 应用程序的工具类。

newApplication() 方法也可接收 Assembly[][][] 类型的参数,由此可创建“千层饼式”分层结构的应用环境(除了第一个和最后一个层,其他都有相邻的上、下层)。例如:

上面代码实现的结构如下图示:

最后,如果应用程序结构十分复杂,还可将 ApplicationAssembly 实例作为参数传递给 newApplication() 方法。 ApplicationAssembly 用类似迭代的形式创建全部 LayerAssembly,再为每个 LayerAssembly 创建 ModuleAssembly。举例如下:

运行上面代码可得到如下结构:

结构化的好处

通过代码显式实现应用程序结构有两个显著的好处:

  1. 就近访问。
  2. 架构强制执行。

这意味着,越近的 Composite 优先级越高,越易访问;外部不能访问模块或层内私有的 Composite。因为服务被实现为 Composite,其解析方法更为含蓄,需要的装配配置也少得多。

Qi4j 结构概念的另一个有趣之处在于每个应用都有一个静态结构组合,它可以通过工具来抽取并展示,而不必单独维护。这使得架构师、设计师或团队负责人可轻松跟踪开发人员对架构的遵循情况,很容易找到越轨者。

总结

本文通过实现于 Java 平台的 Qi4j,简要讨论了 COP 的可行性。我们看到以传统 OOP 观念实现对象的 Composite,是如何更好分离关注点(concerns),从而提升代码的质量和复用性的。此外,我们也讨论了显式建模应用结构的思路,这一结构通常只在纸面上而不是在代码中定义。通过显式建模应用结构,我们可以更容易落实架构执行并消除服务间的相互依赖。这将帮助我们创建更大规模的系统,而且随着引入越来越多的组件及服务,我们的系统不至被其自身的“重量”压垮。

最后要强调的一点是,COP 和 Qi4j 中的绝大多数理念并非前无古人。我们现在做的,恰恰是在前人编程实践和各种框架中寻找各种优秀的思想和模式,并提炼出那些我们认为在编写软件及保持容易理解且易于维护方面都能给开发者提供帮助的内容。无论是开发软件还是我们的日常生活中,将古老的东西运用于新的环境都是非常重要的。

作者简介

Rickard Öberg 曾参与过多个 J2EE 开源项目的开发工作,如 JBoss、XDoclet 和 WebWork。他也是 SiteVision CMS/portal 平台(以 AOP 为基础)的首席架构师。现在服务于 Jayway,主要关注方向是在新一轮以互联网为中心的应用中广泛采用的面向领域软件开发技术。

Jayway 简介

Jayway 是瑞典一家拥有 90 位认证 Java 专家的一流 Java 公司。我们的服务范围包括:内部开发、专业咨询以及 Java 平台相关指导与培训。我们对开源软件有坚定信念,并正为大量开源项目积极工作。我们珍视知识的交流与共享。Jayway 的网站是 www.jayway.com

阅读英文原文: Composite Oriented Programming with Qi4j


译者简介:罗小平,上海某大型公司互联网中心技术总监, CSDN 大版主,网络 ID 为 lxpbuaa(桂枝香在故国晚秋),曾著有《Delphi 精要》一书。个人博客为 http://blog.csdn.net/lxpbuaa ,他的 Email 和 MSN 为 lxpbuaa AT 263.net

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

2009-01-04 20:258176
用户头像

发布了 26 篇内容, 共 76294 次阅读, 收获喜欢 2 次。

关注

评论

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

三到五年互联网公司Java面试题大全

钟奕礼

Java 程序员 java面试 java编程

Java | IO流数据流和标准输出流

陌上

Java 编程 11月月更

【C语言】int 关键字

謓泽

11月月更

2022一线大厂10w字面试总结,每日刷几道,明年金三银四稳了

程序员小毕

spring 程序员 JVM 架构师 java面试

Python进阶(五十三)Flask Web开发实现将表单渲染成HTML

No Silver Bullet

Python flask web开发 11月月更

仅hashmap一道面试题我就搞定了面试官成功入职面试官:我裂开了

钟奕礼

Java java面试 java编程 程序员、

阿里、百度、美团、面试题大集合,愿你更轻松拿下大厂offer

钟奕礼

Java java面试 java编程 程序员、

这个bug,你中招了吗!!!

石臻臻的杂货铺

kafka 后端 11月月更

【Logback+Spring-Aop】实现全面生态化的全链路日志追踪系统服务插件「Logback-MDC篇」

洛神灬殇

log4j logback 全链路追踪 11月日更 MDC

一文搞懂MySQL表字段类型长度的含义

海风极客

MySQL 数据库 11月月更

2022成功入职阿里:阿里的三套Java研发岗面试题总结(文末有答案)

钟奕礼

Java java面试 java编程 程序员、

8年Java开发含泪刷题,架构岗现在好难进,有点崩溃

钟奕礼

Java 程序员 java面试 java编程

2022年华为Java面经,还没搞懂JVM

钟奕礼

Java 程序员 Java 面试 java编程

拿下大厂?这几道jvm面试题必须要懂

钟奕礼

Java 程序员 java面试 java编程

面试中如何才能拿到阿里 P7 的职级?

Java永远的神

Java 阿里巴巴 程序员 架构师 程序员晋升

网络核心笔记(二)

lxmoe

学习笔记 网络 11月月更

亿级万物互联新时代的物联网消息中间件EMQX调研

宋小生

物联网 mqtt emqx

GitHub标星75k,阿里15W字的Spring高级文档(全彩版),真的太香了

程序知音

Java spring ssm java架构 后端技术

2022全网最全最新Java面试题-独家内部教材

钟奕礼

Java 程序员 java面试 java编程

从基础到实战,阿里巴巴高并发系统设计全彩版手册限时开源

Java全栈架构师

程序员 面试 程序员人生 高并发 架构师

如何召回流失用户

穿过生命散发芬芳

11月月更 流失召回

霸榜巨作!阿里内部顶级大佬整理(Redis 5设计与源码分析)

钟奕礼

Java 程序员 java面试 java编程

这20道微服务面试题,阿里、字节、美团、百度面试都问了

钟奕礼

Java 程序员 java面试 java编程

集合工具类Collections指南,以及Comparable和Comparator排序详解

共饮一杯无

Java 集合 11月月更

Java中的String类常用方法

共饮一杯无

Java string 11月月更

Java 后端 100多道面试题,多看点题,没坏处!

钟奕礼

Java 程序员 java面试 java编程

Java | IO流缓冲流和转换流

陌上

Java 编程 11月月更

3年Java研发,突击30天,从14K变成了30K

程序知音

Java java面试 大厂面试 java架构 后端技术

Python冷知识:如何找出新版本增加或删除了哪些标准库?

Python猫

Python

网络核心笔记(一)

lxmoe

学习笔记 网络 11月月更

CleanMyMac2023Mac系统电脑磁盘优化软件

茶色酒

CleanMyMac CleanMyMac2023

用Qi4j进行面向组合编程_Java_Rickard Öberg_InfoQ精选文章