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和相关插件反向所有代码。