.NET设计模式(16):模版方法(Template Method)(转)

摘要:Template Method模式是比较简单的设计模式之一,但它却是代码复用的一项基本的技术,在类库中尤其重要。

主要内容

1.概述

2.Template Method解说

3..NET中的Template Method模式

4.适用性及实现要点

概述

变化一直以来都是软件设计的永恒话题,在XP编程中提倡拥抱变化,积极应对。如何更好的去抓住变化点,应对变化?如何更好的提高代码复用?通过学习Template Method模式,您应该有一个新的认识。

意图

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。[-GOF《设计模式》]

结构图

图1  Template Method 模式结构图

生活中的例子

模板方法定义了一个操作中算法的骨架,而将一些步骤延迟到子类中。房屋建筑师在开发新项目时会使用模板方法。一个典型的规划包括一些建筑平面图,每个平面图体现了不同部分。在一个平面图中,地基、结构、上下水和走线对于每个房间都是一样的。只有在建筑的后期才开始有差别而产生了不同的房屋样式。

图2  使用建筑图为例子的Template Method模式

Template Method模式解说

李建忠老师说过一句话,如果你只想掌握一种设计模式的话,那这个模式一定是Template Method模式。对于这个问题,我想可能是仁者见仁,智者见智,但是有一点不能否认的Template Method模式是非常简单而且几乎是无处不用,很少有人没有用过它。下面我们以一个简单的数据库查询的例子来说明Template Method模式(注意:这个例子在实际数据库开发中并没有任何实际意义,这里仅仅是为了作为示例而已)。

假如我们需要简单的读取Northwind数据库中的表的记录并显示出来。对于数据库操作,我们知道不管读取的是哪张表,它一般都应该经过如下这样的几步:

1.连接数据库(Connect)

2.执行查询命令(Select)

3.显示数据(Display)

4.断开数据库连接(Disconnect)

这些步骤是固定的,但是对于每一张具体的数据表所执行的查询却是不一样的。显然这需要一个抽象角色,给出顶级行为的实现。如下图:

图3

Template Method模式的实现方法是从上到下,我们首先给出顶级框架DataAccessObject的实现逻辑:

public abstract class DataAccessObject

{
    protected string connectionString;

    protected DataSet dataSet;

    public virtual void Connect()

    
        connectionString = 

            "Server=Rj-097;User Id=sa;Password=sa;Database=Northwind";

    }

    public abstract void Select();

    public abstract void Display();


    public virtual void Disconnect()

    {
        connectionString = "";
    }

    // The "Template Method" 

    public void Run()

    {
        Connect();

        Select();

        Display();

        Disconnect();
    }
}

显然在这个顶级的框架DataAccessObject中给出了固定的轮廓,方法Run()便是模版方法,Template Method模式也由此而得名。而对于Select()和Display()这两个抽象方法则留给具体的子类去实现,如下图:

图4

示意性实现代码:

class Categories : DataAccessObject

{
    public override void Select()
    {
        string sql = "select CategoryName from Categories";

        SqlDataAdapter dataAdapter = new SqlDataAdapter(

            sql, connectionString);

        dataSet = new DataSet();

        dataAdapter.Fill(dataSet, "Categories");

    }

    public override void Display()

    {

        Console.WriteLine("Categories ---- ");

        DataTable dataTable = dataSet.Tables["Categories"];

        foreach (DataRow row in dataTable.Rows)

        {

            Console.WriteLine(row["CategoryName"].ToString());

        }

        Console.WriteLine();

    }
}

class Products : DataAccessObject

{
    public override void Select()

    {
        string sql = "select top 10 ProductName from Products";

        SqlDataAdapter dataAdapter = new SqlDataAdapter(

            sql, connectionString);

        dataSet = new DataSet();

        dataAdapter.Fill(dataSet, "Products");

    }

    public override void Display()

    {

        Console.WriteLine("Products ---- ");

        DataTable dataTable = dataSet.Tables["Products"];

        foreach (DataRow row in dataTable.Rows)

        {
            Console.WriteLine(row["ProductName"].ToString());

        }

        Console.WriteLine();

    }

}

再来看看客户端程序的调用,不需要再去调用每一个步骤的方法:

public class App

{
    static void Main()
    {

        DataAccessObject dao;


        dao = new Categories();

        dao.Run();


        dao = new Products();

        dao.Run();

        // Wait for user 

        Console.Read();

    }

}

在上面的例子中,需要注意的是:

1.对于Connect()和Disconnect()方法实现为了virtual,而Select()和Display()方法则为abstract,这是因为如果这个方法有默认的实现,则实现为virtual,否则为abstract。

2.Run()方法作为一个模版方法,它的一个重要特征是:在基类里定义,而且不能够被派生类更改。有时候它是私有方法(private method),但实际上它经常被声明为protected。它通过调用其它的基类方法(覆写过的)来工作,但它经常是作为初始化过程的一部分被调用的,这样就没必要让客户端程序员能够直接调用它了。

3.在一开始我们提到了不管读的是哪张数据表,它们都有共同的操作步骤,即共同点。因此可以说Template Method模式的一个特征就是剥离共同点。

.NET 中的Template Method模式

.NET Framework中Template Method模式的使用可以说是无处不在,比如说我们需要自定义一个文本控件,会让它继承于RichTextBox,并重写其中部分事件,如下例所示:

public class MyRichTextBox : RichTextBox

{

    private static bool m_bPaint = true;

    private string m_strLine = "";

    private int m_nContentLength = 0;

    private int m_nLineLength = 0;

    private int m_nLineStart = 0;

    private int m_nLineEnd = 0;

    private string m_strKeywords = "";

    private int m_nCurSelection = 0;


    protected override void OnSelectionChanged(EventArgs e)

    {
        m_nContentLength = this.TextLength;

        int nCurrentSelectionStart = SelectionStart;

        int nCurrentSelectionLength = SelectionLength;

        m_bPaint = false;

        m_nLineStart = nCurrentSelectionStart;

        while ((m_nLineStart > 0) && (Text[m_nLineStart - 1] != ‘,‘)&& (Text[m_nLineStart - 1] != ‘{‘)&& (Text[m_nLineStart - 1] != ‘(‘))

            m_nLineStart--;

        m_nLineEnd = nCurrentSelectionStart;

        while ((m_nLineEnd < Text.Length) && (Text[m_nLineEnd] != ‘,‘)&& (Text[m_nLineEnd] != ‘}‘)&& (Text[m_nLineEnd] != ‘)‘)&& (Text[m_nLineEnd] != ‘{‘))

            m_nLineEnd++;


        m_nLineLength = m_nLineEnd - m_nLineStart;

        m_strLine = Text.Substring(m_nLineStart, m_nLineLength);

        this.SelectionStart = m_nLineStart;

        this.SelectionLength = m_nLineLength;


        m_bPaint = true;

    }

    protected override void OnTextChanged(EventArgs e)

    {
        // 重写OnTextChanged
    }
}

其中OnSelectionChanged()和OnTextChanged()便是Template Method模式中的基本方法之一,也就是子步骤方法,它们的调用已经在RichTextBox中实现了。

实现要点

1.Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。

2.除了可以灵活应对子步骤的变化外,“不用调用我,让我来调用你”的反向控制结构是Template Method的典型应用。

3.在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法,纯虚方法),但一般推荐将它们设置为protected方法。[李建忠]

适用性

1.一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

2.各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是Opdyke和Johnson所描述过的“重分解以一般化”的一个很好的例子。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

3.控制子类扩展。模板方法只在特定点调用“Hook”操作,这样就只允许在这些点进行扩展。

总结

Template Method模式是非常简单的一种设计模式,但它却是代码复用的一项基本的技术,在类库中尤其重要。

本篇文章写的比较简单,请大家见谅。更多的设计模式文章可以访问《.NET设计模式系列文章》

参考资料

Erich Gamma等,《设计模式:可复用面向对象软件的基础》,机械工业出版社

Robert C.Martin,《敏捷软件开发:原则、模式与实践》,清华大学出版社

阎宏,《Java与模式》,电子工业出版社

Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社

MSDN WebCast 《C#面向对象设计模式纵横谈(14):Template Method模版方法模式(结构型模式)》

时间: 2024-10-13 08:07:57

.NET设计模式(16):模版方法(Template Method)(转)的相关文章

模版方法(Template Method)——类行为型模式

模版方法模式的意图: 定义一个操作中的算法的骨架,TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.即父类已经把算法的流程定义好了,子类只需要改变其中的某些步骤的实现. 就像我们要把东西放入冰箱中,需要的一套完整的流程即为: 打开冰箱,放入物品,关闭冰箱.其中打开和关闭都是固定的,而放入的物品则是不确定的,所以放入的物品需要我们在子类中来具体实现.实例化对象之后,去调用父类中的流程方法(TempleteMethod),就可以完成整个过程.这就是模版方法导

设计模式之模板方法模式(Template Method)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

设计模式 ( 二十 ): Template method模板方法模式 -- 行为型

  1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关.例子1:银行业务办理流程在银行办理业务时,一般都包含几个基本固定步骤:取号排队->办理具体业务->对银行工作人员进行评分.取号取号排队和对银行工作人员进行评分业务逻辑是一样的.但是办理具体业务是个不相同的,具体业务可能取款.存款或者转账. 2.问题 如何保证架构逻辑的正常执行,而不被子类破坏 ? 3.

设计模式二: 工厂方法(Factory Method)

设计模式二: 工厂方法(Factory Method) 简介 工厂方法模式是创建型模式的一种, 核心结构有四个角色: 抽象工厂,具体工厂,抽象产品,具体产品; 实现层面上,该模式定义一个创建产品的接口,将实际创建工作推迟到具体工厂类实现, 一个产品对应一个工厂, 这样的好处是当有新产品引入时可以不修改具体的工厂角色. 意图 定义了一个创建对象的接口,但由子类决定要实例化哪个类.工厂方法把实例化操作推迟到子类. 类图 实现 以汽车举例. 按照本模式核心的四个角色分别定义, 并增加模式调用角色(此处

设计模式 笔记 模版方法模式 Template Method

//---------------------------15/04/28---------------------------- //TemplateMethod 模版方法模式----类行为型模式 /* 1:意图: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.TemplateMethod使得子类可以不改变 一个算法的结构即可重定义该算法的某些特定步骤. 2:动机: 3:适用性: 1>一次性实现算法的不变的部分,并将可变的行为留给子类来实现. 2>各子类中的公共行为应被提取出来并集中

JAVA设计模式之模版方法模式

在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现.这就是模板方法模式的用意. 模板方法模式的结构 模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术. 模板方法模式需要开发抽象类和具体子类的设计师之间的协作

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

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

设计模式(三)Template Method模式

在父类中定义处理流程的框架,在子类中实现具体处理的模式就称为Template Method模式即模板方法模式. 根据下面的示例程序理解模板方法模式. 1 package BigJunOba.bjtu.TemplateMethod; 2 3 public abstract class AbstractDisplay { 4 5 public abstract void open(); 6 public abstract void print(); 7 public abstract void cl

设计模式-模版方法模式

模版方法是一个非常简单,使用频率比较高的设计模式. 意图: 定义一个操作中算法的骨架,而将将一些方法的实现延迟到子类中,TemplateMethod使得子类可以不改变算法的结构即可重定义算法的特定方法. 参与者: AbstractClass,抽象类.定义抽象的操作,具体的子类将重新定义各自的实现算法. ConcreteClass,具体的实现类. 回想一下,在之前的开发中用到过这种模式,简单描述一下场景. 在轻松天气项目中,主程序生成widget,由于widget插件不断的扩充和升级,具体的布局和

设计模式之模版方法模式

1.模版方法模式简介: a.模版方法模式的简单介绍: -  模版方法模式是编程中经常用到模式.它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现.这样,新的子类可以在不改变一个算法结构的前提上重新定义该算法的某些特定步骤. b.核心:处理某个流程中的代码已经都具备,但是其中某个节点的代码暂时不能确定.因此,我们采用模版方法模式,将这个节点的代码实现转移给子类中完成.即:处理步骤父类中定义好,具体实现延迟到子类中定义. 2.简单的代码演示: 在 BankTemplateMethod 类中添加