上一节,我们引入了一个不大不小的变更,然而不经思考的编码却给我们带来了不少麻烦。万不得以,只能重构。
现在臭味消除了,我们Filter类中的InitRules回来了,同时我们也派生了两个规则读取的子类,供过滤器子类使用。
等等,有个问题。你的题目是从抽象到模式,到现在我们都只看到抽象了,那么模式又在哪儿呢?
模式来了,首先我们要引入两个设计模式,分别是Template Method和Strategy。
请看我们的RuleReader,它有一个初始化函数InitRules(),通过调用GetDefaultRules()和GetConfigRules()来完成规则的初始化工作,这里有一点,就是InitRules()不是virtual function,它的逻辑是固定的,子类不需要重写它,而是要重写它所调用的另外两个函数。当客户使用InitRules()的时候,它就会动态地调用子类的GetDefaultRules()和GetConfigRules()。
这就是Template Method,如果某一算法的基本逻辑是不变的,只是其中的几个策略点实现的方式不同,那么我们可以在父类中用一个非虚函数实现算法的基本逻辑,并将可变的策略设计为虚函数供子类继承。
可能用RuleReader做Template Method的实例比较牵强,下面我们引入另一个例子:泛式的快速排序算法。快排的逻辑是固定不变的,但是按从小到大还是从大到小的顺序排列,元素之间大小比较是如何判断的等等,这些策略可能不同,因此可以把算法逻辑提取出来成为父类的非虚接口,同时把排列结果的顺利和大小比较策略抽象化成虚拟的接口,那么我们就可以用子类来具体化一个特定的快速排序算法。
但是Template Method有一个缺点,那就是算法逻辑必须是固定的,当我们需要灵活的算法逻辑时该怎么办呢?没关系,别着急,该是Strategy出场的时候了。
Strategy使用父类定义一个抽象的接口供客户调用,子类可以实现这一接口从而完成不同的算法逻辑。客户把父类的引用(或者指针)作为自己的成员变量,并在客户代码中通过这一引用动态地调用父类提供的抽像接口。当我们把不同的子类对象赋值给父类引用的时候,客户端即可实现不同的算法策略。
那么Strategy在我们的项目中有用到吗?请看我们的PlugIn类中的m_Filters,只是它在那里担当的角色是一个策略组而已。
(未完,待续......)