什么是软件的架构与设计模式

作者:我就是个世界 发表于:2008-04-12
[b][color=#B22222]   软件的架构与设计模式[/color][/b]  转自:[url=http://soft.yesky.com/lesson/495/2012495.shtml]天极网[/url]

  在设计师开始建造一个软件系统之前,必须对这个系统有整体的规划设计,并作出重要的甚至以后无法更改的决定,而这一切都是在设计师头脑中进行的。这个过程就是软件系统的架构设计过程。

  本专题所要讨论的就是软件系统的架构和架构模式,正确地理解架构的概念,掌握架构模式,对于一个软件架构师来说是至关重要的。

导读:
[quote]
[b][color=#990000]一、什么是架构[/color][/b]

[b][color=#990000]二、模式的种类[/color][/b]

[b][color=#990000]三、经典架构模式简介[/color][/b]

[b][color=#990000]四、建筑设计中的层次原则[/color][/b]

[b][color=#990000]五、软件的Layers架构模式[/color][/b]
[/quote][separator]

[b][color=#990000]一、什么是架构[/color][/b]

  什么是软件系统的架构(Architecture)?一般而言,架构有两个要素:

  ·它是一个软件系统从整体到部分的最高层次的划分。

  一个系统通常是由元件组成的,而这些元件如何形成、相互之间如何发生作用,则是关于这个系统本身结构的重要信息。

  详细地说,就是要包括架构元件(Architecture Component)、联结器(Connector)、任务流(Task-flow)。所谓架构元素,也就是组成系统的核心"砖瓦",而联结器则描述这些元件之间通讯的路径、通讯的机制、通讯的预期结果,任务流则描述系统如何使用这些元件和联结器完成某一项需求。

  ·建造一个系统所作出的最高层次的、以后难以更改的,商业的和技术的决定。

  在建造一个系统之前会有很多的重要决定需要事先作出,而一旦系统开始进行详细设计甚至建造,这些决定就很难更改甚至无法更改。显然,这样的决定必定是有关系统设计成败的最重要决定,必须经过非常慎重的研究和考察。

  计算机软件的历史开始于五十年代,历史非常短暂,而相比之下建筑工程则从石器时代就开始了,人类在几千年的建筑设计实践中积累了大量的经验和教训。建筑设计基本上包含两点,一是建筑风格,二是建筑模式。独特的建筑风格和恰当选择的建筑模式,可以使一个独一无二。

  下面的照片显示了中美洲古代玛雅建筑,Chichen-Itza大金字塔,九个巨大的石级堆垒而上,九十一级台阶(象征着四季的天数)夺路而出,塔顶的神殿耸入云天。所有的数字都如日历般严谨,风格雄浑。难以想象这是石器时代的建筑物。

[p align=center][img][attach]27[/attach][/img][/p]

图1、位于墨西哥Chichen-Itza(在玛雅语中chi意为嘴chen意为井)的古玛雅建筑。(摄影:作者)

  软件与人类的关系是架构师必须面对的核心问题,也是自从软件进入历史舞台之后就出现的问题。与此类似地,自从有了建筑以来,建筑与人类的关系就一直是建筑设计师必须面对的核心问题。英国首相丘吉尔说,我们构造建筑物,然后建筑物构造我们(We shape our buildings, and afterwards our buildings shape us)。英国下议院的会议厅较狭窄,无法使所有的下议院议员面向同一个方向入座,而必须分成两侧入座。丘吉尔认为,议员们入座的时候自然会选择与自己政见相同的人同时入座,而这就是英国政党制的起源。Party这个词的原意就是"方"、"面"。政党起源的关键就是建筑物对人的影响。

  在软件设计界曾经有很多人认为功能是最为重要的,形式必须服从功能。与此类似地,在建筑学界,现代主义建筑流派的开创人之一Louis Sullivan也认为形式应当服从于功能(Forms follows function)。

  几乎所有的软件设计理念都可以在浩如烟海的建筑学历史中找到更为遥远的历史回响。最为著名的,当然就是模式理论和XP理论。

  [b]架构的目标是什么[/b]

  正如同软件本身有其要达到的目标一样,架构设计要达到的目标是什么呢?一般而言,软件架构设计要达到如下的目标:

  ·可靠性(Reliable)。软件系统对于用户的商业经营和管理来说极为重要,因此软件系统必须非常可靠。

  ·安全行(Secure)。软件系统所承担的交易的商业价值极高,系统的安全性非常重要。

  ·可扩展性(Scalable)。软件必须能够在用户的使用率、用户的数目增加很快的情况下,保持合理的性能。只有这样,才能适应用户的市场扩展得可能性。

  ·可定制化(Customizable)。同样的一套软件,可以根据客户群的不同和市场需求的变化进行调整。

  ·可扩展性(Extensible)。在新技术出现的时候,一个软件系统应当允许导入新技术,从而对现有系统进行功能和性能的扩展

  ·可维护性(Maintainable)。软件系统的维护包括两方面,一是排除现有的错误,二是将新的软件需求反映到现有系统中去。一个易于维护的系统可以有效地降低技术支持的花费

  ·客户体验(Customer Experience)。软件系统必须易于使用。

  ·市场时机(Time to Market)。软件用户要面临同业竞争,软件提供商也要面临同业竞争。以最快的速度争夺市场先机非常重要。

  [b]架构的种类[/b]

  根据我们关注的角度不同,可以将架构分成三种:

  ·逻辑架构、软件系统中元件之间的关系,比如用户界面,数据库,外部系统接口,商业逻辑元件,等等。

  比如下面就是笔者亲身经历过的一个软件系统的逻辑架构图

[p align=center][img][attach]28[/attach][/img][/p]

图2、一个逻辑架构的例子

  从上面这张图中可以看出,此系统被划分成三个逻辑层次,即表象层次,商业层次和数据持久层次。每一个层次都含有多个逻辑元件。比如WEB服务器层次中有HTML服务元件、Session服务元件、安全服务元件、系统管理元件等。

  ·物理架构、软件元件是怎样放到硬件上的。

  比如下面这张物理架构图描述了一个分布于北京和上海的分布式系统的物理架构,图中所有的元件都是物理设备,包括网络分流器、代理服务器、WEB服务器、应用服务器、报表服务器、整合服务器、存储服务器、主机等等。

[p align=center][img][attach]29[/attach][/img][/p]

图3、一个物理架构的例子

  ·系统架构、系统的非功能性特征,如可扩展性、可靠性、强壮性、灵活性、性能等。

  系统架构的设计要求架构师具备软件和硬件的功能和性能的过硬知识,这一工作无疑是架构设计工作中最为困难的工作。

  此外,从每一个角度上看,都可以看到架构的两要素:元件划分和设计决定。

  首先,一个软件系统中的元件首先是逻辑元件。这些逻辑元件如何放到硬件上,以及这些元件如何为整个系统的可扩展性、可靠性、强壮性、灵活性、性能等做出贡献,是非常重要的信息。

  其次,进行软件设计需要做出的决定中,必然会包括逻辑结构、物理结构,以及它们如何影响到系统的所有非功能性特征。这些决定中会有很多是一旦作出,就很难更改的。

  根据作者的经验,一个基于数据库的系统架构,有多少个数据表,就会有多少页的架构设计文档。比如一个中等的数据库应用系统通常含有一百个左右的数据表,这样的一个系统设计通常需要有一百页左右的架构设计文档。

  [b]架构师[/b]

  软体设计师中有一些技术水平较高、经验较为丰富的人,他们需要承担软件系统的架构设计,也就是需要设计系统的元件如何划分、元件之间如何发生相互作用,以及系统中逻辑的、物理的、系统的重要决定的作出。

  这样的人就是所谓的架构师(Architect)。在很多公司中,架构师不是一个专门的和正式的职务。通常在一个开发小组中,最有经验的程序员会负责一些架构方面的工作。在一个部门中,最有经验的项目经理会负责一些架构方面的工作。

  但是,越来越多的公司体认到架构工作的重要性,并且在不同的组织层次上设置专门的架构师位置,由他们负责不同层次上的逻辑架构、物理架构、系统架构的设计、配置、维护等工作。

[newpage]

[b][color=#990000]二、模式的种类[/color][/b]

  由于[GOF95]是论述软件模式的著作的第一本,也是OO设计理论著作中最流行的一本,因此有些人常常使用设计模式(Design Pattern)一词来指所有直接处理软件的架构、设计、程序实现的任何种类的模式。另外一些人则强调要划分三种不同层次的模式:架构模式(Architectural Pattern)、设计模式(Design Pattern)、成例(Idiom)。成例有时称为代码模式(Coding Pattern)。

  这三者之间的区别在于三种不同的模式存在于它们各自的抽象层次和具体层次上。架构模式是一个系统的高层次策略,涉及到大尺度的组件以及整体性质和力学。架构模式的好坏可以影响到总体布局和框架性结构。设计模式是中等尺度的结构策略。这些中等尺度的结构实现了一些大尺度组件的行为和它们之间的关系。模式的好坏不会影响到系统的总体布局和总体框架。设计模式定义出子系统或组件的微观结构。代码模式(或成例)是特定的范例和与特定语言有关的编程技巧。代码模式的好坏会影响到一个中等尺度组件的内部、外部的结构或行为的底层细节,但不会影响到一个部件或子系统的中等尺度的结构,更不会影响到系统的总体布局和大尺度框架。

  [b]代码模式或成例[/b](Coding Pattern 或 Idiom)

  代码模式(或成例)是较低层次的模式,并与编程语言密切相关。代码模式描述怎样利用一个特定的编程语言的特点来实现一个组件的某些特定的方面或关系。

  较为著名的代码模式的例子包括双检锁(Double-Check Locking)模式等。

  [b]设计模式[/b](Design Pattern)

  一个设计模式提供一种提炼子系统或软件系统中的组件的,或者它们之间的关系的纲要设计。设计模式描述普遍存在的在相互通讯的组件中重复出现的结构,这种结构解决在一定的背景中的具有一般性的设计问题。

  设计模式常常划分成不同的种类,常见的种类有:

  创建型设计模式,如工厂方法(Factory Method)模式、抽象工厂(Abstract Factory)模式、原型(Prototype)模式、单例(Singleton)模式,建造(Builder)模式等

  结构型设计模式,如合成(Composite)模式、装饰(Decorator)模式、代理(Proxy)模式、享元(Flyweight)模式、门面(Facade)模式、桥梁(Bridge)模式等

  行为型模式,如模版方法(Template Method)模式、观察者(Observer)模式、迭代子(Iterator)模式、责任链(Chain of Responsibility)模式、备忘录(Memento)模式、命令(Command)模式、状态(State)模式、访问者(Visitor)模式等等。

以上是三种经典类型,实际上还有很多其他的类型,比如Fundamental型、Partition型,Relation型等等

  设计模式在特定的编程语言中实现的时候,常常会用到代码模式。比如单例(Singleton)模式的实现常常涉及到双检锁(Double-Check Locking)模式等。

  [b]架构模式[/b](Architectural Pattern)

  一个架构模式描述软件系统里的基本的结构组织或纲要。架构模式提供一些事先定义好的子系统,指定它们的责任,并给出把它们组织在一起的法则和指南。有些作者把这种架构模式叫做系统模式[STELTING02]。

  一个架构模式常常可以分解成很多个设计模式的联合使用。显然,MVC模式就是属于这一种模式。MVC模式常常包括调停者(Mediator)模式、策略(Strategy)模式、合成(Composite)模式、观察者(Observer)模式等。

  此外,常见的架构模式还有:

  ·Layers(分层)模式,有时也称Tiers模式

  ·Blackboard(黑板)模式

  ·Broker(中介)模式

  ·Distributed Process(分散过程)模式

  ·Microkernel(微核)模式

  架构模式常常划分成如下的几种:

  一、 From Mud to Structure型。帮助架构师将系统合理划分,避免形成一个对象的海洋(A sea of objects)。包括Layers(分层)模式、Blackboard(黑板)模式、Pipes/Filters(管道/过滤器)模式等。

  二、分散系统(Distributed Systems)型。为分散式系统提供完整的架构设计,包括像Broker(中介)模式等。

  三、人机互动(Interactive Systems)型,支持包含有人机互动介面的系统的架构设计,例子包括MVC(Model-View-Controller)模式、PAC(Presentation-Abstraction-Control)模式等。

  四、Adaptable Systems型,支持应用系统适应技术的变化、软件功能需求的变化。如Reflection(反射)模式、Microkernel(微核)模式等。

[newpage]

[b][color=#990000]三、经典架构模式简介[/color][/b]

  根据Linda Rising的《Pattern Almanac》一书,已知的架构模式有七十多种。这是一个只多不少的统计,其中包括了很多通常认为是设计模式的模式,比如Bridge,Facade,Interpreter,Mediator等模式通常认为是设计模式,但是在许多情况下,也可以作为架构模式出现,因此也常常被当作架构模式。

  [b]Layers架构模式[/b]

  在收集到用户对软件的要求之后,架构设计就开始了。架构设计一个主要的目的,就是把系统划分成为很多"板块"。划分的方式通常有两种,一种是横向的划分,一种是纵向划分。

  横向划分将系统按照商业目的划分。比如一个书店的管理系统可以划分成为进货、销售、库存管理、员工管理等等。

  纵向划分则不同,它按照抽象层次的高低,将系统划分成"层",或叫Layer。比如一个公司的内网管理系统通常可以划分成为下面的几个Layer:

  一、网页,也就是用户界面,负责显示数据、接受用户输入;

  二、领域层,包括JavaBean或者COM对象、B2B服务等,封装了必要的商业逻辑,负责根据商业逻辑决定显示什么数据、以及如何根据用户输入的数据进行计算;

  三、数据库,负责存储数据,按照查询要求提供所存储的数据。

  四、操作系统层,比如Windows NT或者Solaris等

  五、硬件层,比如SUN E450服务器等

  有人把这种Layer叫做Tier,但是Tier多带有物理含义,不同的Tier往往位于不同的计算机上,由网络连接起来,而Layer是纯粹逻辑的概念,与物理划分无关。

  Layers架构模式的好处是:

  第一、任何一层的变化都可以很好地局限于这一层,而不会影响到其他各层。

  第二、更容易容纳新的技术和变化。Layers架构模式容许任何一层变更所使用的技术

  [b]Fa?ade架构模式[/b]

  外部与一个子系统的通讯必须通过一个统一的门面(Facade)对象进行,这就是Facade模式。

  现代的软件系统都是比较复杂的,设计模式的任务就是协助设计师处理复杂系统的设计。

  设计师处理复杂系统的一个常见方法便是将其"分而治之",把一个系统划分为几个较小的子系统。但是这样做了以后,设计师往往仍然会发现一个子系统内仍然有太多的类型要处理。而使用一个子系统的使用端往往只关注一些特定的功能,却要同时与子系统内部的许多对象打交道后才能达到目的,请见下面的对象图。

[img][attach]43[/attach][/img]

图4、Facade架构模式的结构图。

  这就是一种不便,它使得系统的逻辑变得不必要的复杂,维护成本提高,复用率降低。

  用一个范例说明,中国大陆的医院便是一个子系统,按照部门职能,这个系统可以划分为挂号、门诊、划价、化验、收银、取药等。看病的病人要与这些部门打交道,就如同一个子系统的使用端与一个子系统的各个类型打交道一样,不是一件容易的事情。

  首先病人必须先挂号,然后门诊。如果医生要求化验,病人必须首先划价,然后缴款,才能到化验部门做化验。化验后,再回到门诊室,请见下面的对象图。

[img][attach]44[/attach][/img]

图5、描述病人在医院里的体验。图中的方框代表医院。

  解决这种不便的方法便是引进Facade模式。仍然通过医院的范例说明,可以设置一个接待员的位置,由接待员负责代为挂号、划价、缴费、取药等。这个接待员就是Facade模式的体现,病人只接触接待员,由接待员负责与医院的各个部门打交道,请见下面的对象图。

[img][attach]45[/attach][/img]

图6、描述经过Facade模式的改装后,病人在医院里的体验。图中的方框代表医院。

  Facade模式要求一个子系统的外部与其内部的通讯必须通过一个统一的门面(Facade)对象进行。Facade模式提供一个高等级的接口,使得子系统更易于使用。

  使用了Facade模式之后,本章的第一个图中所描述的一个子系统的使用端对象所面对的复杂关系就可以简化为下面这个样子。

[img][attach]46[/attach][/img]

图7、Facade架构模式的结构图

  描述经过Facade模式的改装后,一个子系统的使用端与子系统的关系。图中的大方框代表一个子系统。

  就如同医院的接待员一样,Facade模式的门面类型将使用端与子系统的内部复杂性分隔开,使得使用端只需要与门面对象打交道,而不需要与子系统内部的很多对象打交道。

  [b]Mediator架构模式[/b]

  Mediator模式包装了一系列对象相互作用的方式,使得这些对象不必互相明显参照;从而使它们可以较松散地耦合。当这些对象中的某些对象之间的相互作用发生改变时,不会立即影响到其它的一些对象之间的相互作用;从而可以保证这些相互作用可以彼此独立地变化。

  在下面的示意图中有大量的对象,这些对象既会影响别的对象,又会被别的对象所影响,因此常常叫做同事(Colleague)对象。这些同事对象通过彼此的相互作用形成系统的行为。从图中可以看出,几乎每一个对象都需要与其它的对象发生相互作用,而这种相互作用表现为一个对象与另一个对象的直接耦合。

[img][attach]47[/attach][/img]

图8、这是一个过度耦合的系统

  通过引入调停者对象(Mediator),可以将系统的网状结构变成以中介者为中心的星形结构,如下图所示。在这个星形结构中,同事对象不再通过直接的联系与另一个对象发生相互作用;相反地,它通过调停者对象与另一个对象发生相互作用。调停者对象的存在保证了对象结构上的稳定,也就是说,系统的结构不会因为新对象的引入造成大量的修改工作。

[img][attach]48[/attach][/img]

图9、这是一个使用了Mediator架构模式之后的结构图

  比较传统的设计方法,面向对象的技术可以更好地协助设计师管理更为复杂的系统。一个好的面向对象的设计可以使对象之间增加协作性(Collaboration),减少耦合度(Coupling)。一个深思熟虑的设计会把一个系统分解为一群相互协作的同事对象,然后给每一个同事对象以独特的责任,恰当的配置它们之间的协作关系,使它们可以在一起工作。

  在Mediator模式中,所有的成员对象都可以协调工作,但是又不直接相互管理。这些对象都与一个处于中心地位的调停者对象发生紧密的关系,由这个调停者对象进行协调工作。这个协调者对象叫做调停者(Mediator),而调停者所协调的成员对象称做同事(Colleague)对象。

  在Colleague对象内部发生的事件会影响到所有的同事,但是这种影响不是以直接管理的方式直接传到其它的对象上的。记住在小组的成员增加时,这样的相互作用关系是以比指数更快的方式增加的。相反,这种影响仅仅直接影响到调停者对象,而调停者对象反过来会协调其它的同事,形成整个系统的行为。

  如果小组的成员增加时,调停者对象可能会面临修改,而其它的同事则可以装做不知道这个新的成员一样,不必修改。反过来,如果小组的成员之一被从系统中删除的话,调停者对象需要对此做出修改,而小组中其它的同事则不必改动。

  [b]Interpreter架构模式[/b]

  给定一个语言之后,Interpreter模式可以定义出其文法的一种表示,并同时提供一个直译器;使用端可以使用这个直译器来解释这个语言中的句子。

  如果某一类型问题一再地发生的话,那么一个有意义的做法就是将此类型问题的各个实例表达为一个简单语言中的语句。这样就可以建造一个直译器,通过解释这些语句达到解决问题的目的。

  例如,依照一个匹配模式搜寻字符串便是一个常见的问题。与其为每一个匹配模式建造一个特定的算法,不如建造一个一般性的算法处理各种常规表达式。当接到一个指定的常规表达式时,系统使用一个直译器解释这个常规表达式,从而对字符串进行匹配。

  再比如VBA(Visual Basic for Applications)就不仅仅出现在微软的Office系列软件中,并且可以供第三厂家出产的软件嵌入使用;Crystal Reports报表生成软件也包括了一个便于使用的宏语言,使用户可以执行较为复杂的命令操作。一般而言,将VBA或者其它的语言软件嵌入到自己的软件产品中,可以使产品定制化(Customization)能力大大增强,但是这些宏语言引擎往往都很昂贵。

  现在要介绍的Interpreter模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。熟悉了这个模式以后,一个没有接收过形式语言和编译器的正规训练的设计师也可以自行设计一个简单的直译器,以便为使用端提供一个简单语言,或者在系统内部使用一个简单语言描述一个合适的问题。

  [b]语言、直译器和剖析器[/b]

  Interpreter模式只描述直译器是怎样工作的,并不指明怎样在执行时创建新的直译器。虽然广义地讲直译器不一定要有一个剖析器(Parser),但是使用剖析器仍然是最常见的建立直译器的办法。一个剖析器可以从一个档或命令行读入文字性命令,并创建直译器。

剖析器是一种能够识别文字并将文字按照一定规则进行分解以便进一步处理的对象。剖析器能够识别的字符串叫做语言。通常建立的小型计算机语言是与环境无关的语言,也就是遵循一定的文法的文字模式,所谓文法,便是决定怎样将语言的元素组合起来的规则的集合。剖析器便是根据组合规则将字符串分解的。

  抽象地讲,语言并不一定是以字符串的形式表达的。在Interpreter模式里面所提到的语言是指任何直译器对象能够解释的任何组合。在Interpreter模式中,需要定义一个代表文法的命令类型的等级结构,也就是一系列的组合规则;每一个命令对象都有一个解释方法,代表对命令对象的解释。

  命令对象的等级结构中的对象的任何排列组合都是一个语言,而剖析器的工作便是将一个文字性语言翻译成为等效的直译器语言。因此,直译器往往需要剖析器。

  [b]认识Jack吗[/b]?

  剖析器生成器(Parser Generator),常常称为编译器的编译器(Compiler Complier)。Sun Microsystem提供一个专为Java程序员发明的强大的剖析器生成器,最初叫做Jack,后来改名为JavaCC。

  要使用JavaCC,必须使用它提供的脚本语言编写一个脚本,然后执行JavaCC生成Java源代码。这生成的源代码就是所需的剖析器。现在Sun已经不再负责JavaCC的研发,对JavaCC感兴趣的读者可以从http://www.experimentalstuff.com/Technologies/JavaCC得到免费的JavaCC和相关数据。

  JavaCC最早命名为Jack是为了与一个早就广泛使用的剖析器生成器YACC谐音。如果读者已经熟悉了YACC,可以使用YACC达到同样的目的;只是相比之下JavaCC更容易得到Java程序员的喜爱。



[newpage]

[b][color=#990000]四、建筑设计中的层次原则[/color][/b]

  计算机软件工业是一个年轻的工业,它诞生于1950年,至今不过五十几年的历史。相比之下,建筑设计则可以追溯到几千年前埃及金字塔时代,甚至更早。因此,计算机软件设计师可以从建筑设计师那里学习到非常之多的经验和教训。计算机软件系统的设计和建筑设计有很明显的相似之处。

  如果读者到过纽约华尔街附近的话,会发现那里大量的古老雄伟的地标性建筑群中散布着一些超豪华住宅建筑,十分不和谐。其实这些建筑本是昂贵的办公大楼,建筑结构极为牢固,只是因为大楼的设计老旧,无法适应架设计算机通讯设备、以及电梯改造等等需求,而不得不改造为住宅。这一波发生在八十年代的IT设备革新的浪潮导致了大量的建筑物被拆毁重建,这些被改造为住宅的仅仅是其中少数幸存下来的。

  著名的建筑设计学家Steward Brand考察了上千所古今建筑物,特别是它们在落成和投入使用之后所发生的事情。他发现在建筑物的设计中,层次的概念是基本的原则。

  Steward Brand说,好的建筑都是为变化而设计的(Built for Change),从古至今,人类所建造的千千万万的建筑物,其成功与失败全在于是否能够适应需求的变化。但是怎么做到这一点呢?Steward Brand说:"一个好的架构应当将变化的与不变的层次分开" ,也就是按照可变性的不同,将建筑物划分成为不同的变化层。

[img][attach]30[/attach][/img]

图10、Steward Brand所提出的六个S原则,描述建筑物的设计。

 [b] 六个S[/b]

  英国建筑学院院长Frank Duffy说,"我们的基本观点是根本就不存在’一栋建筑’这样的概念。"为什么这样说呢?"一栋建筑"是一个固体的概念;而作为一个固体的建筑物并不存在,真正存在的是一个流体,它处在不断的流动和变化之中,本身可以按照流速划分成几个不同的层次。

  在文献[BRAND94]中,Steward Brand进一步发展了这个概念。他指出,建筑物可以划分成为六个层次:

  ·Site(地点)、建筑物所在的地理位置,建筑用地的形状如何等。建筑用地上面的建筑每过几十年的时间就会被推倒重来,但是建筑用地会长久存在。

  ·Structure(结构)、建筑的基础结构部分非常难以改变,改变起来也非常昂贵。一般而言,基础结构的生命就是建筑物本身的生命。基础结构的生命通常可以长达三十年到三百年,当然由于其他的原因,很少有建筑物寿命超过六十年的。

  显然,建筑物的主体结构的稳固性仅次于地点的稳固性。无论是钢结构的还是混凝土结构建筑,其主体结构都是非常难以改变的,即便较小的改变所需代价都大得难以承受。

  Windows操作系统从9x版本不断升级到XP版本,其内部的变化就如同建筑物的主体结构变化一样,是非常昂贵的变化。

  ·Skin(外表)、这就是建筑物的外表。因为时尚、信仰、技术革命、大规模整修等原因,一般建筑物的外表每过二十年左右就会发生一次变化。比如最近对节省能源的关注导致建筑物外表更加密闭和绝缘。

  显然,建筑物外表的稳固刑部能够与建筑物的主体结构相比。在建筑物的主体结构不变的情况下,外表可以发生适当的变化。熟悉Windows操作系统的读者都目睹了从Windows 3.x到Windows 9x以及Windows 2000的图形用户界面所发生的变化,一个早期开发的应用程序,在不需要修改的情况下,就可以"变脸"。

  ·Service(服务)、这是建筑物的五脏六腑:通讯电缆、电源线、排水、供暖、通气和空调等,以及建筑物内部的可动部分,比如电梯、自动楼梯等。每过7到15年这些部分就磨损了。很多情况下,这些容易磨损的部分非常紧密地嵌入到建筑物的结构中,以至于无法简单地更换它们,就只好将建筑物推倒重来。

  因此,建筑物的设计必须允许服务部分进行不断的更新,以便为建筑物的住户或者商家提供与时具进的服务。

  ·Space Plan(空间规划)、建筑物内部的墙、天花板、地板、门等如何分布。商业空间的规划常常会因为部门重组而发生变化,一般每三年就改变一次;而住宅空间有时每三十年才发生变化。

  显然,空间的规划受制于建筑物的基本结构和服务。

  ·Stuff(摆设)、这是一些大家都非常熟悉的物品,比如办公室里面的文件、电话、盆景、废纸篓,家庭的床、洗漱间、照片、厨房设施、灯、发梳等,这些东西每月、每周、每日、每时都会变化。

  这些装饰物的使用取决于建筑物的内部空间规划,而不是相反。

[img][attach]31[/attach][/img]

图11、Steward Brand所提出的六个S原则,描述建筑物的设计。

  这就是建筑学的层次设计原则,其关键就是按照结构的稳固度对建筑物的结构进行划分。稳固度的反面就是变化的可能性;这一设计原则按照变化的难易程度将结构分割成不同层次,位于最底部的是最稳固、最难以改变的结构,越往上就是稳固性越低、变化越容易的结构。

因此Frank Duffy说,作为一个设计师,你应当避免为一个五分钟的问题提供一个五十年的解决方案,也不要为一个五十年的问题提供一个五分钟的解决方案。建筑设计师、服务工程师、空间计划师、室内装修师应当解决不同时间尺度上的问题。

[newpage]

[b][color=#990000]五、软件的Layers架构模式[/color][/b]

  建筑学的设计原则也应当成为软件系统设计的指导原则。

  第一种情况

  这也就是最为熟知的情况。客户端向第N层发出请求,而第N层不能独立完成请求,需要调用第N-1层所提供的服务,第N-1层同样需要他的下级,也就是N-2层所提供的服务。如此往复,直到第2层和第1层。

  第1层可以独立完成自己的任务,它将执行的结果返还给第2层。第2层得到第1层的结果之后,便能够继续完成自己的任务了,它会把执行的结果继续向上,也就是第3层传递。如此反复,一直到第N-1层和第N层。

[img][attach]32[/attach][/img]

图12、在有N个层次的架构中,请求(Request)沿着层次自上向下传递,结果(Result)自下向上传递。

  系统的客户端只知道第N层,它向第N层发出请求,并且从第N层接到结果,客户端并不知道其他层次的存在。参见下图。

[img][attach]33[/attach][/img]

图13、客户端只知道第N层,而不知道其他层次。

  第二种情况

  这第二种情况代表了自下至上的通讯,称为通知(Notification)。这一系列的行为开始于第1层,这一层通过处理后,将通知向上传给第2层,继续向上传递到第3层,一直到第N-1层和第N层为止。参见下图。

[img][attach]34[/attach][/img]

图14、在有N个层次的架构中,Notification沿着层次自下向上传递。

  使用过USB设备的读者知道,一旦把USB设备插入到计算机中的时候,USB驱动软件立刻就会发现设备被激活,并通知设备的设备操作软件,设备操作软件便会启动。这一系列的行为就是Notification自下向上传递的过程。

  在第一种情况中,请求首先向下传递,然后结果逆向传递,形成一个环形。在第二种情况中,Notification的传递是单向的。

  第三种情况

  这一种情况与第一种情况相似,只是仅涉及到一部分的层次而已。

  首先客户端向第N层发出请求,而第N层不能独立完成请求,需要调用第N-1层所提供的服务,第N-1层同样需要他的下级,也就是N-2层所提供的服务。如此往复,直到第J层为止。

  第J层可以独立完成自己的任务,而不再需要J-1层。它将执行的结果返还给第J+1层。第J+1层得到第J层的结果之后,便能够继续完成自己的任务了,它会把执行的结果继续向上,也就是第J+2层传递。如此反复,一直到第N-1层和第N层。参见下图。

[img][attach]35[/attach][/img]

图15、在有N个层次的架构中,Request向上传递到某个中间层次就停止了,Result从那里向下传递。

  同样,客户端只知道第N层,而不知道其他层次的存在。


  第四种情况

  这种情况描述的是Notification自下向上传递的过程,只是第二种情况涉及到全部的N各层次,而这里仅涉及到一部分的层次而已。参见下图。

[img][attach]36[/attach][/img]

图16、Notification自第1层向上传递到某个中间层次就停止了,通讯过程是单向的。

  首先,全部的行为开始于第1层,这一层通过处理后,将通知向上传给第2层,继续向上传递到第3层,一直到第J层为止,不会再向上传递。

  第五种情况

  此种情况涉及到两个层次结构,两个结构之间相互通讯,常常称作协议层次结构(Protocol Stacks)。在下面的图中,左边的第N层发出请求,这个请求向下传递,经过N-1层,…第2层直到第1层。

  这个时候,请求被接着传递给右边的第1层,然后沿着层次结构向上传递,经过第2层,第3层等等,一直到第N-1层和第N层。

[img][attach]37[/attach][/img]

图17、请求从左边的第N层向下传递到第1层,然后传递到右边。

  执行的结果自右边的第N层开始向相反传递,经过右边的第N-1层,N-2层,…第2层、第1层,然后返回到左边的第1层,再沿着左边的层次结构向上传递,经过第2层,第3层,…到达第N-1层,回到第N层。

[img][attach]38[/attach][/img]

图18、结果从右边的第N层向下传递到第1层,然后传递到左边。

  两端的客户端A和B都只知道各自的第N层,而不知道其他层次,它们会认为在两个层次之间存在一个联结,其实这个联结是虚拟的,是通过其他层次进行的。

[img][attach]39[/attach][/img]

图19、客户端A发出请求给左边的第N层,经过中间的过程之后,到达右边的第N层,然后传递到右边的客户。

  TCP/IP的层次结构

  TCP/IP的设计显然是依循层次原则设计的,参见下图。

[img][attach]40[/attach][/img]

图20、TCP/IP的设计图。

  无循环依赖原则(ADP)

  在层次的相互依赖关系中,不允许出现循环依赖关系。比如下面的图中显示了从第N层到第N-1层的依赖,从第N-1层到第J层的依赖,从第J层到第2层的依赖,从第2层到第1层的依赖;这都是没有问题的。但是图中还有一个从第J层到第N层的依赖关系。这就造成了一个循环的依赖关系,而这种循环依赖关系时应当避免的。

[img][attach]41[/attach][/img]

图21、出现了循环依赖关系。

  假象每一层都由一个木板代表,木板一层压着一层摆放。上层的木板就会依赖于下层的木板,这就是依赖关系。这样的依赖关系是不可能循环的,因为欧几里德几何学不会允许。如果硬要设计出循环依赖关系的话,就只好伪造几何学,参见下图。

[img][attach]42[/attach][/img]

图22、不可能的几何:在三维欧几里德空间中无法实现这样的几何结构。

分享:

扫一扫在手机阅读、分享本文

请发表您的评论