Refactoring to Patterns 项目实践

         摘要:通过重构实现、趋向和去除模式,这是我从Kerievsky那本叫Refactoring to Patterns的书中看到的。
而今天文章的内容是一种对其思想的实践案例。有趣的是在这篇文章中所说到的代码开发和重构过程发生在
2006年7月份, 而我看到的这本书的相关内容只是两天前的事。我在这里不是想说自已的思想与作者已经走
到了一起,而是想说作者的思想也是从实践中来的,而我们的编程也是一种实践,这必然会有相交的可能。
这也是为什么实践类的文章会如此受欢迎的原因。
 
          废话不多说了。


          应用场景:论坛模版生成类和用户定制生成类

          模式名称:Template Method (模版方法)

          在开始设计论坛的模版生成功能时,其实一开始程序很简单,只是用如下的方法来直接生成相关的模版
页面:

          class PageTemplate
          {
                  //skinName 所用的皮肤名字(这与模版所存放的文件夹对应)
                  //templateName 要生成的模版页的名称
                  public static GetTemplate(string skinName, string templateName, 
          ......


          而在外面只是用一个普通类包装了一下这个方法而已。因为设计需求就是这么简单。

          但到了2006年 7月份,情况发生了变化,用户反映应该有按用户自定义变量来生成模版的功能,换句话说
我们需要改进一下上面的那个函数了。起初我们只是想把自定义功能直接写一个方法,然后把方法的调用放到
上面的那个函数里。但当我们完成了这个小改动后准备去做别的功能时(当时开发任务非常重,经常是要同时
开发几个功能),雪人发现如果将来要支持第三方做模版功能的后续开发时,眼下的这个设计是无论如何也无
法让用户满意的。就这样,雪人很快写出了如下的类来继承自上面的那个方法的封装类:
 
        public class ForumPageTemplate : PageTemplate
       {
              public ForumPageTemplate()
              {
              }

              /// <summary>
              /// 解析特殊变量
              /// </summary>
              /// <returns></returns>
              public override string ReplaceSpecialTemplate(string skinName,string strTemplate)
              {
                        ....第三方或用户自定义模版变量要实现的功能
              }

             public override string GetTemplate(string skinName, string templateName, int nest,int templateid)
           {
                  return base.GetTemplate(skinName,templateName,nest,templateid);
           }

         我们设计的想法也是很简单,只想当用户调用这个类的GetTemplate 方法时,先直接调用基类PageTemplate
中的方法,这里出现了基类上的第二次变动。首先我们把基类改成了abstract类型,然后在基类中声明了如下的
函数:
            public abstract string ReplaceSpecialTemplate(string skinName,string strTemplate);  
            接着又去在基类的GetTemplate方法中加入对新增抽象函数的调用。

            在编译通过后,发现程序执行顺序如下,即:
            1.    先运行ForumPageTemplate.GetTemplate()
            2.    接着运行PageTemplate.GetTemplate()
            3.    PageTemplate.ReplaceSpecialTemplate()方法(当然,这是个抽象方法,它会返回并直接运行第4步)
            4.    ForumPageTemplate.ReplaceSpecialTemplate

            基本上按我们想的执行顺序运行着,就这样我们完成了这次改造(或可以称作是重构)。

         到这里可能有人会说为什么不用 virtual去实现上面的PageTemplate类中ReplaceSpecialTemplate方法,而要用
abstract 呢?其实这也有我们的考虑, 因为我们自己定义的模块翻译过程如果我们自己去用的话,是不应该存在
去写一个ReplaceSpecialTemplate方法,因为根本没有必要。这个函数只是用于对应一些特殊的模版,如第三方定
制或用户自己增加的模版变量, 因此只是简单的用了abstract  来标记。另外因为virtual 的使用势必会增加系统运行
时内存资源的消耗(这方面资料可以看一下多年前侯捷翻译的那本《c++对象模型深度探索》)。
    
         当我们完成工作后去吃中午饭的路上,我脑子里突然冒出了一张图,也就是DP上说的Template Method 的图,
原来我们不知不觉已把这种模式在这次改造中利用上了,越想越觉得有意思。因为在这之前,我个人一直是习惯
于在软件设计时就先用模式来打框架的,而在开发时是很不愿意做这种程序类结构上的大幅变化的。不过当看到
这段程序经过我们这么一翻“折腾”后,功能加强了,结构也条理了,也能拿得出手了,心里还是感到很欣慰的。

         最后再套用《重构》书中的一句话“设计模式重构提供了目标”。即使达到不了目标的彼岸,也要死在这
条通往目标的路上。因为目的只有一个,就是在不改变软件现有功能的基础上,通过调整程序代码改善软件的质
量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。

          代码示例:
          http://nt.discuz.net 最新的论坛版本。
   
          说明:
          PageTemplate类位于             Discuz.Common.DLL
          orumPageTemplate类位于     Discuz.Forum.DLL
          为了表明开源的决心,我们的代码未进行加密处理,可直接用reflector和相关插件反向所有代码。
   

posted @ 2006-12-21 14:18  代震军  阅读(2733)  评论(1编辑  收藏  举报