软件体系结构

本文深入探讨了MVC、PAC、管道和过滤器等架构模式,以及Abstract Factory、Builder等设计模式的应用与原理,旨在帮助读者理解这些模式如何提高软件的可维护性和灵活性。

MVC模式

 

定义
       模型-视图-控制器(MVC,Model-View-Controller)体系结构模式将一个交互式应用程序分为三个组件。模型包含核心功能和数据。视图向用户现实信息。控制器处理用户输入。视图和控制器共同构成用户接口。变更-传播机制确保了用户接口和模型之间的一致性。

结构
       简单来说,MVC模式用来指导那些有GUI界面并且希望界面能够变化的交互式系统的构建。主要的目的就是将“内容”和“形式”分离。
       MVC将一个交互式系统分为输入、输出和数据处理三部分,分别对应了视图、控制器和模型。由于在GUI下面,输入输出其实比想象中要紧密,所以视图和控制器其实耦合的程度会很高,构成了直接和用户打交道的前端。而模型则构成了后端。
       视图最为内部数据的表现形式,为了达到和模型解耦合的目的,通常用Observer模式连接起来。简单的说,就是模型作为信息的提供者,每个需要这些信息的视图会先向模型注册一下,模型记录了当前对自身信息感兴趣的视图。当模型中的数据发生变化的时候,通过视图提供的接口通知视图“信息发生了变化”,然后视图再向模型详细查询信息的具体内容。
       控制器与模型的关系与M-V的关系类似,控制器在接收到用户的输入的时候,通过调用模型的接口来将输入或者经过处理的输入传告诉模型。

效果
       MVC模式将模型严格与用户接口分开,所以同一模型可以支持多视图,改变视图并不会影响模型。
       但是,可以看到,在MVC模式中,模型是主要的,视图是依赖于模型的。所以,模型很难随意改变而不影响视图和控制器。另外,除了只读视图,视图和控制器基本很难分开。另外,频繁的数据更新也会使得视图需要经常查询数据,造成系统性能下降。

PAC模式定义
       表示-抽象-控制(Presentation-Abstraction-Control,PAC)体系结构模式以合作agent的层次形式定义了交互软件系统的一种结构。每个agent负责应用程序功能的某一特定方面,并且由表示、抽象和控制三个组件构成。这种细分将agent的人机交互与其功能内核和它与其他agent的通信分隔开来。

结构
       PAC模型以树状层次结构构建交互式应用层次。PAC agent共分三层:顶层PAC agent,底层PAC agent和中层PAC agent。但要注意的是,PAC并不是每个字母对应一层。后面,出现“agent”的地方与“PAC agent”同义。
       顶层agent负责系统的核心功功能。比如说建立在一个数据仓库上的应用程序,顶层agent就相当于访问数据仓库的接口。
       底层agent表达了独立的语义概念。比如,负责显示功能的agent,柱状图、饼图等各种视图都可以通过一个agent来控制。底层agent负责直接跟用户打交道,也就是除了显示数据还可以接收输入。
       中层agent则是负责沟通底层和顶层agent。注意中层agent并不一定直接就和底层agent通信。因为中层agent中也可以分层次,高级别的中层agent管理低级别的中层agent,这个就有点像树里面的非叶子节点。
       个人认为说agent分为三层还不如说agent分为三类。虽然,这样表述系统层次结构不太明显,但是起码不会和层次模型混淆。
       与MVC模型比较,PAC负责UI的底层agent不再依赖于核心功能的顶层agent。其关键在于加进了中层agent作为它们直接的桥梁。这样,核心功能和显示真正的分开,而可以分别实现修改而不会严重影响系统其他部分。另外一个关键点是,agent之间通过一种尽可能小的接口进行通信(比如只有send和receive),那么当某些agent要做修改,它只要保持通信内容格式的一致性,其他的agent就不需要作修改。

效果
       Agent在实现的时候可以很容易分到独立的进程或线程中,所以PAC模式很容易支持多任务和分布式。各个agent之间的耦合降到很低,所以变化和扩展都很容易。
       这种模型同时也存在一些问题,其中比较主要的就是通信的开销。特别是在中层agent层次较深的时候,这个问题尤其明显。
       PAC模型两个已知应用是网络通信量管理,也就是中心管理agent以及派出的多个监测agent。另一个例子是移动机器人。
定义
    管道和过滤器(Pipes and Filters)体系结构模式为处理数据流的系统提供了一种结构。每个处理步骤封装在一个过滤组件中。数据通过相邻过滤器之间的管道传输。重组过滤器可以建立关系系统族。

简述
    典型的例子是编译器。编译器中的数据流动是单向的,也就是源程序按顺序经过各个阶段的加工,最终编程目标代码输出。
    如果阶段之间的接口定义明确,那么功能的改变都可以限制在单个过滤器里面。这样替换单个过滤器的影响基本不会影响别的过滤器。
    如果确实系统的功能就很显然地符合管道模式的要求,或者确实有办法抽象成这样的模型,那么它确实是非常简单而优秀的解法。但是,管道模式有内在的单向性,后面的过滤器不能向前面的过滤器反馈信息。这种单向性在于一些需要各个部分有协商的应用中显得非常不合适。
    不管怎么说,从UNIX的管道发展而来的管道模式提供了一种优秀的设计思想。

定义
    层(layer)体系结构模式有助于构建这样的应用:它能被分解成子任务组,其中每个子任务处于一个特定的抽象层次上。

简述
    TCP/IP协议是一个分层的很好例子。而互联网的兴旺则可以很好地说明这种模式的强大。
    层模式的核心思想就是抽象,这个也是处理复杂系统的“圣剑”。层次模型可以说是模式中的模式。通过一层一层的抽象剥落系统的复杂性,而使得每一层的用户仅仅看到与自身直接相关的接口,而屏蔽了与用户无关的扰乱人心的细节(这里说提到的用户不一定是最终的用户——人,可能是使用到这层服务的更高层的程序)。剥离无关的细节的过程也是剥离复杂性的过程。
    层次模式和管道模式的区别在于:层次模型的层次之间是调用关系,,而管道模型的过滤器是顺序执行不同的加工过程。也就是,层次是一个由上往下的调用过程,以及由下往上的返回过程。而管道仅仅是源数据按顺序经过各个过滤器。

定义
    映像(Reflection)体系结构模式为动态地改变软件系统地结构和行为提供一种机制。它支持如类型和函数调用机制等基本方式的修改。在这种模式中, 一个应用程序可分成两个部分。一个元层次提供所选系统属性的相关信息并使软件含自述信息。一个基本层次包括应用程序逻辑。它的实现建立在元层次之上。改变 保存在元层次之上的信息会影响其后在基本层次上的行为。

简述
    映像模式包括的两个层次之间的关系就像是设备(基本层次)和设备说明书(元层次)一样。而设备说明书的编写要按照一定的规范(元对象协议),以保证用户知 道在哪里能找到需要的东西。这类系统特征是,功能的实现是可变的,描述功能实现的说明书(元对象)内容是可变的,而不变的是修改和使用说明书的手段(元对 象协议)。
    在使用映像模式的系统中,各个基本层次类之间的调用都通过访问元对象实现。当基本层次作出修改的时候,则不需要对其他部分的源代码进行修改。这里可以通过 元对象层次提供的接口来描述变化,这样,变化就会反映在代表它的那个元对象上面。这样别的需要这个类的对象就可以通过访问新的元对象无缝使用新的接口。当 然,这里元对象内部状态改变后,对于它的所有引用要进行更新。
    这个模式有对于修改很好的适应性,使得更改软件系统变得容易。但是会造成系统复杂,组件增多,效率降低等不良影响。造成系统复杂几乎是高级一点的模式共有的缺点。通过引入额外的复杂性得到的易修改和松耦合的特性能不能弥补维护的代价那就要看具体实现的考量了。
   

  设计模式是在面向对象设计时候的经验的总结。主要是为了使得应用模式的代码获得某种特性而对设计进行某种限制。其实总观大部分设计模式的目的无非就是解耦合,所用的手段大体上就是封装变化。
     这里的封装变化笔者的理解是,一个功能模块中某些部分可能需要经常更改,而另外一些部分可能并不需要经常更改,所以需要把要常更改的和不常更改的代码隔离开,避免“牵一发而动全身”。这里体现的思想就是解耦合,而实际模式所要说的问题是在什么地方解耦合。这里,我们所说的封装变化从设计模式视角来看可以分成三类:从不变中抽取变化,从变化中抽取不变,将变化与变化分来。而像这样组合的话,其实还有一类是将不变与不变分开,当然这张分开和不分开其实区别都不大了。
     我们逐个分析GoF书中经典的23个设计模式可以发现,大部分的模式都符合这个理解。不过,需要说明的是,像设计模式这种经验类的知识,并不是说必然符合,其实笔者的观点是很多的模式符合这一思想,但是也有一些模式并不是为了解决耦合问题,所以并不符合这个思想。对于这类模式,暂时只能归结到“其他”类了。软件体系结构之七——设计模式

设计模式分析
1 Abstract Factory
    同样的接口(也就是同一类对象),但是希望能在不同的环境中有不同实现,而使用这些对象的客户(Client)程序不作改变。所以,封装构造函数,从不变中抽取变化。
2 Builder
    根据需求建立具有相同接口的对象。封装构造函数,从不变中抽取变化。
3 Factory Method
    封装构造函数,从不变中抽取变化。Factory Method和Abstract Factory在形式上几乎没有区别。但是,在用途和原则是不一样的。AF让一族的类使用相同的创建接口,强调的是整体性,主要使用继承来实现多态。FM则通过组合不同的实现类来体现功能的变化,强调局部性,主要是采用组合不同的子类来实现多态。
4 Prototype
    将一些不变的配置做成模版,避免重复劳动。变化中抽取不变。
5 Singleton
    全局之能有一个对象,虽然引用它的对象可以多变。从变中抽取不变。
6 Adpter
    对于已有的两个组件,如果逻辑上能够合作,但是接口却不合,那么就把被调用一方包装(wrap)成合适的接口。抽取的是变化关系(或者说接口),把变化的关系和变化的实现分开。
7 Bridge
    接口可能需要扩展,实现也要改变,所以接口的interface和实现的interface分开,这样它们就可以分别改变。也就是将变化与变化分来。
8 Composite
    所有对象抽象在同一概念下,然后组织成层次关系。(还不知道如何归类软件体系结构之七——设计模式
9 Decorator
    对已有的东西作小扩展,保持原有接口不变。(还不知道如何归类软件体系结构之七——设计模式
10 Facade
    把系统总结构的组织抽取出来,那么系统结构和子系统能够分别变化。变化与变化分离。
11 Flyweight
    用层次关系组织大量的对象,像更加严格的Composite。
12 Proxy
    构造一个间接的访问层。实现“懒”策略或者提供附加策略(类似Decorator)。
13 Chain of Responsibility
    将各个模块组织成有向无环图,消息通过在图中游走得到适当的处理。这里提供了一种灵活的处理结构。这里是分离变化。
14 Command
    将命令(或者说操作、动作)封装成对象。这样,可以用一致的方式访问不同的命令,提供操作上的灵活性。
15 Interpreter
    完全按照规约编程。低效但是清晰。
16 Iterator
    将顺序访问的行为封装出来,能够用同样的形式操作不同的集合对象。从变化抽取不变。
17 Mediator
    将各部分的交互集中到一起。这里是封装了关系。从变化中抽取不变。至少不变的是关系的形式。
18 Memento
    保存对象的状态,以便恢复。
19 Observer
    增加一个辅助的消息,解开主从的耦合。
20 State
    从局部的状态的角度看有限状态机。通过每个state对于自己转化的知识产生正确的系统行为。类似于Facade模式把系统结构的信息分解到每个子系统对自己的邻居的知识。
21 Strategy
    算法会变,抽取出来。不变中抽取变化。
22 Template Method
    多个步骤的复杂处理过程,提取过程的框架。类似于Facade的Prototype。
23 Visitor
    将目标(element)和操作(visitor)分开,使得可以根据element的具体实现或实际需要加载visitor。

    以上就是根据封装变化的思想对于设计模式的一些理解。其中难以归入这类的是那些通过增加特性或设施(Decorator、Observer、Menento...)以及按照特殊的方式组织模块结构(Composite、Interpreter...)的模式。这个方面还有待改进。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值