首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

软件接口设计

Software Interface Design

将软件分层意味着我们需要完成额外的工作——设计层次之间的接口。我们原来拥有的是一大块代码,现在则会有三处不同的代码块(业务逻辑、交互逻辑和标记),它们当中的每一块都需要和下一块交流。但是仔细考虑一下这样做是否的确造成了额外的工作?答案十有八九是否定的:分析一下我们现在仅有的那一层代码,会发现这些附加劳动早就完成了,只有逻辑层和标记层之间的交流还不是很明确,和其他剩余代码混在了一起。

为什么要花心思在分层上呢?不管怎么说,在某种程度上,原来的那种所有代码都粘在一起的程序风格还是可以工作的。然而,有几个决定性的因素,它们将我们引向分层实现,而且随着系统规模逐步扩大,这些因素会一个比一个地变得更为重要。层次分离,让不同的工程师或工程师小组可以同时工作在系统的不同层次,而不用担心无意中影响了他人的工作。除了工作对象变成了不同的物理文件之外,这些小组也不再需要对其他层次有深入了解。标记层的工作人员不必理解数据是如何从数据存储中取出,并且传给模板系统的,他们只需要知道一旦这些数据交付给了他们,应该如何去使用这些数据。类似的,工作重

点在交互层逻辑的工程师也不需要理解在取得一条数据的背后,系统逻辑层是如何运作的,而只需要知道用相应的函数调用就可以了。在这些例子中,工程师们惟一需要关注的元素就是自己所在层次的内容和所在层次与上层和下层的接口。那么,我们一直谈论的接口到底是什么呢?要知道当我们谈的是软件层次之间的接口时,所指的并不是Java中的面向对象概念上的接口。我们所说的接口,描述的是允许一个层次和另一个层次之间交换请求和响应的一组特性。对数据层与系统逻辑层而言,接口包括对原始数据的存储和抽取。对交互逻辑层与系统逻辑层,接口包括对特定类型数据源的修改。接口仅仅定义一个层次如何向另一个层次发出请求,要求它执行一个任务,而不管这个任务如何执行。

我们的应用程序中最为顶端的层次是比较不一样的,因为标记层与表现层之间的接口已经由我们所采用的技术定义好了。标记层到样式表的链接使用的是链接标记符或者@import语句,通过它们获得class和id属性,以及样式表中的命名的标记符序列,根据这些可以应用特定的样式规则。为了保持良好的层次分离,在标记层中应尽量避免直接使用样式属性。本书并不包含前端工程的内容,但前端分层的原因和后端分层的原因是相同的——分离样式层与标记层,才能让不同团队可以独立地工作于项目的不同方面,并且开发人员可以进行层次内部修改,而不用担心影响相邻层次。

交互逻辑层和标记层进行交流的典型方式是模板系统。在PHP和Smarty参考实现中,Smarty为PHP交互逻辑层提供若干功能。我们可以调用 Smarty的方法来将数据导出到模板(继而用于输出),也可以调用Smarty的方法来提供在模板内执行的展现函数,甚至还可以自己直接渲染模板。在某些情况下,我们需要的并不是直接得到模板的输出,然后将输出发送给终端用户。比如在发送电子邮件的时候,我们可以在模板系统中为它创建一个模板,导出所需要的数据和功能,把这个模板渲染到交互逻辑层的一个变量中,然后发送这封邮件。采用这种做法时,要注意到数据与控制不仅是单向流动的,控制在所有层次之间都可以双向传递。

两个逻辑层之间的接口,根据具体实现,很可能是最容易理解的,也是最难以设计的。如果两个层次使用的是同一种语言,接口可能只是一组函数。这时,接口的设计包括决定命名方案(用于函数命名)、调用方案(用于加载正确的库,以使函数可用),以及数据方案

(用于将数据向前或向后传输)。所有这些方案都算在系统逻辑层逻辑模型的概要设计中。我喜欢将可能的设计选择画成一个连续的光谱图,称之为网络应用犯傻程度:

OGF <---------- 心智健全----------> 面向对象程序设计

这个光谱往左是单个的巨型函数,往右则接近面向对象程序设计。老式的、单一的Perl系统在光谱中非常靠左,而Zope和Plone的位置在右边。更为有趣的一些模型则沿光谱分布,其中MVC群体集中在中心三分之一处。像Struts和Rails这一类的框架,则分布在右侧靠近Zope的地方(这提醒了你接下来会发生什么)。Flickr在中间稍偏左,它采用类似MVC的方式,但没有使用框架,随着时间的推移和系统的越来越复杂,它也逐渐向右偏移。

你选择定位在光谱上的哪一个位置进行工作,那完全是个人偏好问题。往右走,就以灵活性为代价,获得可维护性。往左走,就丧失可维护性,获得灵活性。偏离中心越远,优化系统就会越困难,但系统架构就会越简单。当前趋势是明确地远离左侧,而中右侧的框架越来越受到欢迎。但始终要牢记,你往一个方向移动,并获得某种好处的同时,也会失去一些别的东西。

堆栈最底部的层次总有定义比较完美的接口,因为它们物理上是分离的——你总不会想用PHP来实现自己的数据库吧?所以这一块的接口定义和层次分离总是以抽象层次的形式发生在应用程序代码内部。业务逻辑层没有必要知道物理上如何连接到数据库集群,但是建立连接的代码需要知道如何连接。分离的数据库与存储层从系统逻辑层获取指令,连接到数据存储,执行指令并返回结果。例如,业务逻辑层可能知道它需要执行一些SQL语句,并知道需要在哪个集群上执行这些语句,它就可以进行如下调用:

$result = db_query('my_cluster', 'SELECT * FROM Frobs;')

接下来就是存储层的责任了,它的代码要连接到正确的服务器,执行命令并返回结果。执行查询的服务器可能发生变化(交换硬件时),可能被复制(也许用于冗余故障转移),可能被记入日志并进行基准测试(参阅第8章中的MySQL小节),或者执行任何我们决定的操作。这个例子中的接口是db_query( )函数和它的伙伴们。对于文件存储层而言,接口中可能包含store_file( )函数,给它传入文件名后,接着就由它来表演魔术了。这个魔术本身怎样和系统逻辑层无关,我们只要执行了需要的调用,就能得到需要的结果。

接口设计在Web应用程序体系结构中扮演着最主要的角色。接口会随着时间而演变,接口变动时,负责不同层次工作的团队必须得进行协商,但是这些更改应该只牵涉到小部分当前开发的内容。在不会无意中破坏其他部分的情况下,我们能在单个层次内做的越多,生产效率就越高,灵活性也越高。

AB

Getting from A to B

构建大型应用程序时打下好的基础很重要,但避免在适用于大型应用的基础之上构建小型应用程序也同样重要,所以需要某种途径来进行不同规模之间的转换。可能我们有一个系统,整个就是“一个巨大的函数”,也可能我们正在构建原型,这个原型以后要拓展成为大型应用程序。在建造原型时,可以跳过系统体系结构设计的条条框框让产品尽快能运行。一旦要让这些小系统和原型系统真的派上用场,就必须将它们的基础夯实,并强制应用特定的结构以适应大型系统。

由小系统变成大系统的第一个步骤通常是将展现层分离出来,将原本内嵌的标记分离到模板文件中。这个过程可以细化成三个不同的任务,三个任务可以独立完成,这样可以避免一次性剧烈的改变。这种办法让你在分离模板的同时,不影响主开发过程,因此能避免开发过程的中止。这三个步骤如下:

将逻辑代码从标记代码中分离出来

第一步就是将生成HTML标记的代码分离出来,存入到一些新文件中,在运行时用页面驱动文件包含这些新文件。这一步完成时,逻辑代码与标记生成代码便会存在于不同的文件组中,但也不排除有可能多个页面的标记都是由某个单一文件生成的。

将标记代码划分成一个文件对应一个页面

由于可以预计会切换到一个模板系统,所以要将每个页面或者可重用的页面组件分离成各自的文件。到目前为止,还在使用老的常规代码来生成标记,但每个逻辑标记段(页或块)都有它自己相应的文件。

切换到模板系统

做到页面和生成文件一一对应之后,就可以逐个转变这些页面到模板系统。这可以是一个缓慢的过程,尤其是有大量逻辑混杂在标记生成代码中时。但因为早就对不同页面进行了划分,所以可以在任意一页上花任意长的时间来转换,而不会影响到别的页面。

一旦你把模板部分很好地划分了出来,你就会接着想把样式分离到CSS文件中(如果你还没有这样做)。如何管理到CSS的迁移,这个问题超出了本书的范畴,然而在网络上有很多自由格式的优秀资源。

标记层和展现层从代码库中分离之后,仅剩的任务是分离页面逻辑和业务逻辑。有多种办法可以实现这个目标,但其中最为简易的、又能部分实现目标的一种是函数分组。

仔细查看系统中的数据操作部分,并把它们划分为各个函数组,就可以快速为业务逻辑设计好模块化结构。其中一种很简单的办法是将访问某张数据库表(或相关数据库表集合)的代码划归为一组。你可以处处留心这样的代码,它们或读或写,但都访问这些表以实现业务逻辑层的功能。在Flickr中,对存放照片注释(这些照片的注释部分)的表的读和写就包含在一个单独的模块中。这种方法也能让业务逻辑修改简单化。如果需要对数据库表或者存放于其中的内容进行任何更改,我们立即就知道在哪儿能找到处理这张表的所有代码。

和模板层的分离一样,业务逻辑和页面逻辑的分离也可以经历很长的时间,通过一个逐步的过程来完成。随着各个不同功能域被划分出来,层次会变得越来越明显,到最后,所有的数据访问都安排在业务逻辑的类库中,而所有的交互逻辑则仍然保留在页面驱动逻辑文件中。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论