深入浅出设计模式——模板方法模式(Template Method Pattern)

模式动机

模板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一。在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中。
在模板方法模式中,我们需要准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来让子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意。模板方法模式体现了面向对象的诸多重要思想,是一种使用频率较高的模式。

模式定义
模板方法模式(Template Method Pattern):定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板方法是一种类行为型模式
Template Method Pattern: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
Frequency of use: medium
UML图

模式结构
模板方法模式包含如下角色:
AbstractClass: 抽象类
ConcreteClass: 具体子类

模式分析
模板方法模式是一种类的行为型模式,在它的结构图中只有类之间的继承关系,没有对象关联关系。
在模板方法模式的使用过程中,要求开发抽象类和开发具体子类的设计师之间进行协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。实现这些具体逻辑步骤的方法称为基本方法(Primitive Method),而将这些基本法方法汇总起来的方法称为模板方法(Template Method),模板方法模式的名字从此而来。

模板方法:一个模板方法是定义在抽象类中的、把基本操作方法组合在一起形成一个总算法或一个总行为的方法。
基本方法:基本方法是实现算法各个步骤的方法,是模板方法的组成部分。
 抽象方法(Abstract Method)
 具体方法(Concrete Method)
 钩子方法(Hook Method):“挂钩”方法和空方法

在模板方法模式中,由于面向对象的多态性,子类对象在运行时将覆盖父类对象,子类中定义的方法也将覆盖父类中定义的方法,因此程序在运行时,具体子类的基本方法将覆盖父类中定义的基本方法,子类的钩子方法也将覆盖父类的钩子方法,从而可以通过在子类中实现的钩子方法对父类方法的执行进行约束,实现子类对父类行为的反向控制。

模式实例与解析
考题抄错会做也白搭—模板方法模式
体系结构

TestPaper.cs

using System;

namespace TemplateMethodPattern
{
    //金庸小说考题试卷
    class TestPaper
    {
        //试题1
        public void TestQuestion1()
        {
            Console.WriteLine("杨过得到,后来给了,炼成倚天剑、屠龙刀的玄铁是[] a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维");
            Console.WriteLine("答案:" + Answer1());
        }
        //试题2
        public void TestQuestion2()
        {
            Console.WriteLine("杨过、程英、陆无双铲除了情花,造成[] a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化");
            Console.WriteLine("答案:" + Answer2());
        }
        //试题3
        public void TestQuestion3()
        {
            Console.WriteLine("蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[] a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对");
            Console.WriteLine("答案:" + Answer3());
        }

        protected virtual string Answer1()
        {
            return "";
        }
        protected virtual string Answer2()
        {
            return "";
        }
        protected virtual string Answer3()
        {
            return "";
        }
    }
}

TestPaperA.cs

using System;

namespace TemplateMethodPattern
{
    //学生甲抄的试卷
    class TestPaperA : TestPaper
    {
        //试题1
        public new void TestQuestion1()
        {
            base.TestQuestion1();
        }
        //试题2
        public new void TestQuestion2()
        {
            base.TestQuestion2();
        }
        //试题3
        public new void TestQuestion3()
        {
            base.TestQuestion3();
        }
        protected override string Answer1()
        {
            return "b";
        }
        protected override string Answer2()
        {
            return "a";
        }
        protected override string Answer3()
        {
            return "c";
        }
    }
}

TestPaperB.cs

using System;

namespace TemplateMethodPattern
{
    //学生乙抄的试卷
    class TestPaperB : TestPaper
    {
        //试题1
        public new void TestQuestion1()
        {
            base.TestQuestion1();
        }
        //试题2
        public new void TestQuestion2()
        {
            base.TestQuestion2();
        }
        //试题3
        public new void TestQuestion3()
        {
            base.TestQuestion3();
        }
        protected override string Answer1()
        {
            return "d";
        }
        protected override string Answer2()
        {
            return "b";
        }
        protected override string Answer3()
        {
            return "a";
        }
    }
}

Client:客户类

using System;

namespace TemplateMethodPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("学生甲抄的试卷:");
            TestPaper studentA = new TestPaperA();
            studentA.TestQuestion1();
            studentA.TestQuestion2();
            studentA.TestQuestion3();

            Console.WriteLine("学生乙抄的试卷:");
            TestPaper studentB = new TestPaperB();
            studentB.TestQuestion1();
            studentB.TestQuestion2();
            studentB.TestQuestion3();

            Console.Read();
        }
    }
}

模式优缺点
模板方法模式的优点
 模板方法模式在一个类中形式化地定义算法,而由它的子类实现细节的处理。
 模板方法模式是一种代码复用的基本技术。
 模板方法模式导致一种反向的控制结构,通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为,符合“开闭原则”。

模板方法模式的缺点
 每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,但是更加符合“单一职责原则”,使得类的内聚性得以提高。

模式适用环境
在以下情况下可以使用模板方法模式:
 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
 对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。
 控制子类的扩展。

【声明与感谢】
本文,站在许多巨人的肩膀上,借鉴和引用了许多他人拥有版权的作品或著述,在此,对前人们的贡献致谢。并同时公布引用的内容、原作者或来源(一些来源于互联网的内容本人无法追述本源,深表遗憾)。

【参考文献】
《设计模式—可复用面向对象软件的基础》作者: [美] Erich Gamma / Richard Helm / Ralph Johnson / John Vlissides 译者: 李英军 / 马晓星 / 蔡敏 / 刘建中 等 机械工业出版社
《重构—改善既有代码的设计》作者: Martin Fowler译者:候捷 中国电力出版社
《敏捷软件开发—原则、模式与实践》作者: Robert C. Martin 清华大学出版社
《程序员修炼之道—从小工到专家》作者: Andrew Hunt / David Thomas 电子工业出版社
《Head First 设计模式》作者: 弗里曼 译者: O'Reilly Taiwan公司 中国电力出版社
《设计模式之禅》 作者: 秦小波 机械工业出版社
MSDN WebCast 《C#面向对象设计模式纵横谈》 讲师:李建忠
刘伟. 设计模式. 北京:清华大学出版社, 2011.
刘伟. 设计模式实训教程. 北京:清华大学出版社, 2012.
《大话设计模式》 作者: 程杰 清华大学出版社
《C#图解教程》作者: 索利斯 译者: 苏林 / 朱晔 人民邮电出版社
《你必须知道的.NET》作者: 王涛
《项目中的.NET》作者: 李天平 电子工业出版社
《Microsoft .NET企业级应用架构设计》作者: (美)埃斯波西托等编著 译者: 陈黎夫
http://www.dofactory.com/Patterns/Patterns.aspx .NET Design Patterns
http://www.cnblogs.com/zhenyulu 博客作者:吕震宇
http://www.cnblogs.com/terrylee 博客作者:李会军
http://www.cnblogs.com/anlyren/ 博客作者:anlyren
http://www.cnblogs.com/idior 博客作者:idior
http://www.cnblogs.com/allenlooplee 博客作者:Allen lee
http://blog.csdn.net/ai92 博客作者:ai92
http://www.cnblogs.com/umlonline/ 博客作者:张传波
http://www.cnblogs.com/lovecherry/ 博客作者:LoveCherry

posted @ 2015-01-04 11:50  Bobby0322  阅读(608)  评论(0编辑  收藏  举报