绑定模型和实现

模型种类繁多,目的各有不同,即使是那些金用于软件开发项目的模型也是如此。领域驱动设计要求模型不仅能够指导早期的分析工作,还应该成为设计的基础。这总设计方法对于代码的编写有着重要的暗示作用。比太明显的一点就是:领域驱动设计要求一种不同的建模方法......

 

模式:MDD(Model-Driven Design)

 

那些压根没有领域模型的项目,仅仅通过编写代码来实现一个有一个功能,他们无法利用知识消化和沟通所带来的好处如果涉及复杂的领域就会使项目举步维艰。

 

另一方面,许多复杂的项目确实在尝试使用一些领域模型,但是并没有把代码的编写与模型紧密联系起来。这些项目所设计的模型,在项目初期还可能用来作一些探索工作,但是随着项目的进展,这些模型与项目渐行渐远,甚至还会起到误导作用。所有模型上话费的精力都无法保证程序设计设计的正确性,因为模型和设计是不同的。

 

模型和程序设计的凉席可能在很多情况写被破坏,但是二者的这种分离往往是有意而为之的。很多设计方法都提倡使用完全脱离与程序设计的分析模型,并且通常祥和而这时有不同的人员开发的。之所以称其为分析模型,是因为它是对业务领域进行分析的结果,他在组织业务领域中的概念时,完全不去考虑自己在软件系统中将会起到的作用。分析模型仅仅是理解工具,人们认为把它与程序实现联系在一起无异于搅浑一池清水。随后的程序设计与分析模型之间可能仅仅保持一种松散的对应关系。再常见分析模型时并没有考虑程序设计的问题,因此分析模型很有可能无法满足程序设计的需求。

 

如果整个程序设计或者其核心部分没有与领域模型相对于,那么这个模型就是没有价值的,软件的正确定也值得怀疑。同时,模型和设计功能之间太过复杂的对应关系也是难于理解的,在实际项目中改变设计时也无法维护这种关系。分析和设计工作全无关联,导致在这两个过程中所获得的知识无法彼此共享。

 

MDD模型驱动设计不再将分析模型和程序设计分离开,而是寻求一种能够满足这两方面需求的单一模型。不考虑纯粹的技术问题,程序设计中的每个对象都反映了模型中相应概念。这就要求我们以更高的标准来选择模型,因为他必须同时是想两种完全不同的目标。

 

很多方法可以対领域进行抽象,也有很多种设计可以解决应用程序的问题。因此绑定模型和程序设计是切实可行的。但是这种绑定不能够因为技术考虑而削弱分析的功能,我们也不能接受那些只反映了领域概念却舍弃了软件设计原则的拙劣设计。将领域模型和程序设计紧密联系在一起是绝对是必要的,这也使得在众多可选模型中选择最实用的模型时,又多了一条选择标准。

 

因此:

软件系统各个部分的设计应该忠实的反应领域模型,以便体现出这二者之间的明确对应关系。我们应该反复检查并修改模型,在软件中更加自然的实现模型,及时向然他反映出更深层次的领域概念也应如此。我们需要的模型不但应该满足这两种需求,还应该能够支持健壮的Ubiquitous Language。

从模型中获取用于程序设计和基本任务分配的术语。程序代码就是模型的表达,修改代码可能就是改变模型。而模型的改变势必会影响到接下来的相应的项目活动。

完全依赖模型的实现通常需要支持建模范式的软件开发工具和语言,比如面向对象的编程。

 

建模范式和工具支持

 

为了使MDD发挥作用,一定要在可控范围内严格保证模型与设计之间的一致性,必须要运用有软件工具支持的建模范式,他可以直接模拟模型中的概念。

面向对象编程之所以功能强大,是因为它基于建模范式,并且为模型构造提供了实现方式。从程序员的角度来看,对象那个真实存在内存中,他们与其他对象相互联系,他们被组织成类,并且通过消息传递来完成相应的行为。

面向对象设计是目前大多属大象项目所使用的建模范式。

 

实例:从过程设计到Model-Driven Design

 

我们可以把PCB看做是连接各种电路元件引脚的电导体(net)的集合。电路板上通常会有成千上万个net。有一种叫做PCB布局工具的专用软件,能够为所有net安排物理布局,而不会使他们相互交叉或干扰。它的实现方法就是根据设计者规定的大量限制条件来限制布局方式以及优化路径选择。尽管PCB布局已经非常先进了,但是他仍然有一些缺陷。

 

其中一个问题就是这些数以千计的net都各自拥有一套布局规则,PCB工程师认为根据net自身的性质可以将其分组,同组的net应该公用相同的规则。比如,有些net构成了总线。

 

工程师每次用8个、16个或者256个net组合成总线,这样布局工作就更易于管理了,不但提高了效率也减少了错误。问题是布局工具中没有类似于总线这样的概念。布局规则不得不应用于成千上万个net,每次处理一个net。

 

机械设计:

 

在布局工具的这种限制下,无计可施的工程师只能编写脚本来分析布局工具的数据文件,然后将规则直接插入到文件中,最后再把他们应用与整个总线。

布局工具在net列表文件中存储每一个电路连线,如下:

 

Net Name Component.Pin

------------ -------------------

Xyz0 A.0, B.0

Xyz1 A.1, B.1

Xyz2 A.2, B.2

......

 

而布线规则被存储在类似于下面格式的文件中:

 

Net Name Rule Type Parameters

----------- ------------ ---------------

Xyz1 min_linewidth 5

Xyz1 max_delay 15

Xyz2 min_lineWidth 5

Xyz2 max_delay 15

......

 

工程师为net指定严格的命名约定,这样将数据文件的内容按照字母排序,就可以使构成同一条总线的所有net都排列在一起。然后他们编写的脚本就可以解析该文件并且基于总线来修改每个net。用来解析、处理和写入文件的实际代码太过冗长晦涩,对解释这个例子没有什么帮助,下面只列出这个处理过程的重要步骤。

 

1.按照net名称将net列表文件排序;

2.逐行读取文件,寻找以总线名称开头的第一行数据;

3.解析名称匹配的每一行,获取每行中的net的名称;

4.将net名称和规则文本附加到规则文件的末尾;

5.从第3步起重复执行,知道没有匹配该总线名称的行。

总线规则的输入文件采用如下的格式:

 

Bus Name Rule Type Parameters

------------- ------------ ---------------

Xyz max_vias 3

 

经过处理后,输出的是添加了net规则的文件,如下所示:

 

Net Name Rule Type Parameters

------------ ------------- ---------------

. . . . . .

Xyz0 max_vias 3

Xyz1 max_vias 3

Xyz2 max_vias 3

. . . . . .

 

我猜想第一个编写这个脚本的人只有这种简单的需求,如果情况确实如此,那么使用这样的脚本是完全合理的。

脚本的编写者试图在布局工具中的领域模型中补充“总线”这个概念,他们的脚本通过排序和字符串匹配来判断总线的存在,却没有明确的定义总线概念。

 

Model-Driven Design

 

前面我们已经描述了领域专家思考问题时所使用的概念。现在需要一些概念组织成模型,作为软件开发的基础。

 


用面向对象语言实现上图的这些对象后,核心功能的实现会变得的轻而易举。

方法assignRule()可以再抽象类AbstractNet中实现。而类Net中的方法assignedRules()则分配了自身的规则以及类Bus的规则。

 

 

abstract class AbstractNet {
	private Set rules;
	
	void assignRule(LayoutRule rule) {
		rules.add(rule);
	}
	
	Set assignedRules() {
		return ruels;
	}

}

class net extends AbstraceNet {
	private Bus bus;
	
	Set assignedRules() {
		Set result = new HashSet();
		result.addAll(super.assignedRules());
		result.addAll(bus.assignedRules());
		return result;
	}
}

 

当然,程序还需要大量的支持代码,但上面的代码片段已经实现了脚本的基本功能。这个程序还需要输入、输出逻辑,我们可以将其概括为一些简单的服务。

 

 

服务职责
Net List import读取Net列表文件,为每一行数据创建Net实例
Net Rule exoprt                     已知Net集合,将所有附加规则写入规则文件

我们还需要几个工具类

职责
Net Repository提供通过名称访问Net的接口
Inferred Bus Factory          已知Net集合,利用命名约定来推断总线,并且创建总线实例
Bus Repository提供功过名称访问Bus(总线)的接口

 

现在,启动应用程序,用输入数据来初始化Net和Bus仓库。

 

Collection nets = NetListImportService.read(aFile);
NetRepository.addAll(nets);
Collection busses = InferredBusFactory.groupIntoBusses(nets);
BusRepository.addAll(busses);

上面提到的服务和仓库都可以进行单元测试。更重要的是还可以测试核心领域逻辑。

Model-Driven Design 易于扩展,能够为规则的组合设置限制条件,还能提供一些其他的一些增强功能。

Model-Driven Design 也为测试提供了方便。它的组件都具有定义完善的接口,可以进行单元测试。而测试脚本程序的唯一方法就是将输入、输出文件进行端到端比较。

 

记住这样的设计不是一撮而就的。我们需要反复研究领域知识,不断重构模型,才能将领域中重要的该概念提炼成简单而清晰的模型。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值