模板方法(TemplateMethod)

首先谈论一下模板方法的重要性和意义所在,其实,很多人都应该使用过模板方法了,

只是他们自己没有意识到而已,比如,您新建一个 Form 或者是 Page 的时候便是使用了模板方法,

因为窗体继承自 Form 而页面则是继承自 Page ,在这里您便可以把 Form 和 Page 看做是一个模板,

而我们在自己的窗体或者是页面中的操作只不过是定义了属于我们自己的具体算法而已。

模板方式模式是基于继承的代码复用的基本技术,同时也是一种比较简单的设计模式,

也可以说模板方法模式的结构和用法也是面向对象设计的核心。

        

        

下面来看模板方法模式的定义

Define the skeleton of an algorithm in an operation,

Deferring some steps to subclasses,

Lets subclasses redefine certain steps of on algorithm without changing the algorithm’s structure。

也就是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,不改变算法的结构而重定义它的一些步骤。

简单的说,模板方法就是用来定义一个算法的模板,而这个模板中的一些具体的实现便放到子类中来完成。

模板方法模式中有抽象类和具体类之分,

抽象类给出一个算法的的轮廓和骨架,另一些具体类则给出这个算法的各个逻辑步骤,

代表这些具体逻辑步骤的方法称为基本方法,而将这些基本方法总汇起来的方法就是模板方法了。

            

              

下面就该来看看模板方法模式的结构类图了

image

从上面的类图中可以看出,在抽象类 AbstractClass 中定义了一个 TemplateMethod ,也就是模板方法,

并且在其中定义了算法的骨架,而至于算法的具体实现却放在了 ConcreteClass 中。

          

           

需要注意的是,模板方法和策略模式的区别,

模板方法的话,是由抽象类定义一个算法的骨架,而后由子类来具体实现算法中的逻辑。

策略模式的话,是封装了可以相互替换的多个行为(也就是算法),然后便可以在客户端动态决定采用那一种行为。

为了区别,下面再贴出策略模式的结构类图,还请注意两者之间的区别。

image

            

            

下面还要介绍一下的是好莱坞原则,

在好莱坞中,当演员把简历递交给好莱坞娱乐公司后,

所能做的就只有等待了,好莱坞公司会告诉他们:“不要打电话给我们,我们会打电话给你”。

很明显,好莱坞原则体现出了好莱坞公司对整个娱乐项目的完全控制,

而应聘的演员只是被动的服从安排,在需要的时候完成流程中的一个具体环节就 OK 了。

在 OO 中来考虑以上的好莱坞原则的话,可以改写为不要调用我们,我们会调用你,

这有什么好处呢?

通过好莱坞原则,我们允许底层的组件和系统发生关系,

但是至于什么时候调用或者是如何调用这些底层组件就是由高层组件来决定了。

也就是高层组件就充当了好莱坞公司,而演员就充当了底层组件,

所以高层组件对底层组件的原则就是:别调用我,我会调用你即高层组件调用底层组件。

而好莱坞原则在模板方法模式中的应用就是:抽象类会告诉其具体子类:“不要调用我们,我们会调用你”。

          

        

下面看一下模板方法模式的具体代码

AbstractClass 的代码

namespace TemplateMethod
{
    /// <summary>
    /// 抽象类
    /// 定义并且实现了一个 TemplateMethod 方法
    /// 并且在其中声明了逻辑的组成步骤
    /// 只不过定义为抽象方法
    /// 使得这些方法必须延迟到子类中实现
    /// </summary>

    public abstract class AbstractClass
    {
        /// <summary>
        /// 声明逻辑的组成步骤
        /// 并且定义为抽象方法
        /// </summary>

        public abstract void PrimitiveOperation1();
        public abstract void PrimitiveOperation2();

        /// <summary>
        /// 在这个模板方法中定义了算法的基本骨架
        /// 基本骨架就是先调用基本方法1
        /// 再调用基本方法2
        /// </summary>

        public void TemplateMethod()
        {
            PrimitiveOperation1();
            PrimitiveOperation2();

        }
    }
}

下面就来看两个具体类 ConcreteClassA 和 ConcreteClassB 的具体代码

using System;

namespace TemplateMethod
{
    public class
ConcreteClassA:AbstractClass
    {
        public override void PrimitiveOperation1()
        {
            Console.WriteLine("抽象类中定义的算法骨架的第 1 步在具体类 A 中的实现");
        }

        public override void PrimitiveOperation2()
        {
            Console.WriteLine("抽象类中定义的算法骨架的第 2 步在具体类 A 中的实现");
        }
    }
}

        

using System;

namespace TemplateMethod
{
    public class
ConcreteClassB : AbstractClass
    {
        public override void PrimitiveOperation1()
        {
            Console.WriteLine("抽象类中定义的算法骨架的第 1 步在具体类 B 中的实现");
        }

        public override void PrimitiveOperation2()
        {
            Console.WriteLine("抽象类中定义的算法骨架的第 2 步在具体类 B 中的实现");
        }
    }
}

客户端的代码

using System;

namespace TemplateMethodTest
{
    class Program
    {
        static void Main(string[] args)
        {
            TemplateMethod.AbstractClass abstractClass;
            abstractClass = new TemplateMethod.ConcreteClassA();
            abstractClass.TemplateMethod();

            Console.WriteLine();

            abstractClass = new TemplateMethod.ConcreteClassB();
            abstractClass.TemplateMethod();

            Console.Read();
        }
    }
}

效果

image

       

           

以前在《大话设计模式》上看到一个关于模板方法模式的比较好的例子,

那里面举的是一个考试卷子的例子,为什么说这个例子好的,

因为您可以把考试卷子看做是抽象类中的模板方法,而把每一个学生写的答案呢,

看做是对算法逻辑的具体实现,也就是一个填充的问题,把考试卷子看做是一个模板,

那么每一个同学都只要往这个模板里面填充属于自己的东西就可以了,既然是考试卷子的话,

填充的就是当然答案了,这样的话,每一位同学所要填写的就是答案了,

这样的话,也实现了代码得最大程度复用。

           

           

           

       

posted @ 2010-05-12 18:38  小宝马的爸爸  阅读(1901)  评论(1编辑  收藏