首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

再谈关切分离, 基于版本控制的设计

2013-10-08 
再谈关注分离, 基于版本控制的设计前段时间写了一篇关于关注分离的博客。很巧的是这段时间我们需要在项目里

再谈关注分离, 基于版本控制的设计

    前段时间写了一篇关于关注分离的博客。很巧的是这段时间我们需要在项目里增加一个新特性,又提到了关注分离。背景是这样的:我们有一个ConfigManager类,这个类的职责是读取和写入配置文件。当业务逻辑有配置文件读写要求时,直接调用ConfigManager即可,使得配置文件对业务逻辑完全透明。当时在设计ConfigManager类的时候考虑到了配置文件的格式有可能在将来会改变,实现可能会有bug,所以加入了配置文件的版本号。两周前,我们发现这个ConfigManager类在遇到某类配置时会抛exception,于是提交了一个patch修这个bug,并将版本号升到1.1。可是提交这个patch不久,我们又发现在某个特殊情况会引发另一个exception,不得不再提交一个patch并升级到1.2。于此同时我们遇到了一个无法回避的兼容性问题:在安装,卸载软件时,我们通常是不会删除配置信息的。也就是说客户本来安装了1.0的软件,当升级到1.1时,软件的版本号升级了,但是配置信息还是1.0的。在只有两三个版本信息的时候这件事还是很好办的,我们只需要每次读取配置文件的时候检查版本号,如果不是最新的版本就升级到最新。但是如果版本很多,并且跨越时间又很长时,这就是个很严重的问题了: 首先需要讲以往所有的配置文件处理搞明白,然后将其升级到最新。举个极端情况,如果已经升级过100次了, 第101次不得不把前面所有的版本实现复习一遍,找出不同,然后升级。我们想到了版本控制。仔细考虑这个问题我们会发现做升级的时候我们只需要循环实现将n-1次版本升级到下一个版本,直到最新。这样一来每次只需要考虑一次升级。这里还要考虑一个小问题:这种渐进式的升级并不是每次都能奏效,举个简单的例子: v1 -> v2 -> v3。 v1升级到v2会使信息丢失,这样从v2到v3的升级就会导致丢失的信息无法复原。所以我们需要有一种机制做到v1->v3的升级。把这个分析用伪代码写出来应该是这样的:

    Version Upgrade(Version currentVersion)

    {

           Version version = currentVersion;

           While( IsLatestVersion( version ) == false)

           {

                  Version nextVersion = version.Next;

                  while( IsStable( nextVersion) == false) nextVersion = nextVersion.Next;

                  version = nextVersion.UpgradeFrom( version );

           }


           return version;

    }

最外层的Upgrade函数从来渐进式的控制版本的升级。 IsLatestVersion用来判断是否已经是最新的版本了,IsStable用来判断该版本是否稳定(处理v1->v3这种情况)。每一个稳定版本有一个UpgradeFrom函数,这个函数才是真正做升级用。

  回过头来看这个升级过程,我们会发现实际上它和ConfigManager并没有多大关系。两者之间的纽带只是那个配置文件中的版本号。所以,我们应该把版本控制的部分从配置类里抽出来,单独实现VersioinController类。这样任何含有版本信息的逻辑都可以通过这个VersionController类统一升级。现在我们已经把版本控制从配置类中剥离出来了。我们接下来继续研究如何实现这个版本控制类。

    如果只考虑升级过程,不考虑降级(downgrade),我们不难发现这是一个有向无环图的操作,每一个图结点可以有k个入边, 但只有一个出边。 即任意一个版本只能升级到一个新的版本,但是可以从k个之前的版本升级过来。如下图所示。


       v1 -----> v2      v3 ----------> v4 ------> v5

                       |                            ^

                       |                            |

                      +---------------------+

现在我们又将问题从讨论如何进行版本升级转化为: 处理图结构 + 版本升级。将责任进一步的剥离。

如下图所示:

再谈关切分离, 基于版本控制的设计

VersionController保存了图结点集合(graphNodes),每个图结点的content域保存了Version信息。

Register函数用来生成这张有项无环图。Upgrade函数用来升级Version。但是和上面实现有些不同,这里遍历图结点的过程是基于Node,一旦到达某一个结点,会调用该结点的Visit来处理,在Visit内部调用Version的Upgrade。


   总结:通过关注分离,我们将原来配置文件里一个bug的修复转化为实现一个版本控制类,在改类的实现中,我们又进一步划分为图操作和版本升级。



热点排行