首页 > 其他分享 >第15章 模版方法模式(Template Method)

第15章 模版方法模式(Template Method)

时间:2023-06-11 14:07:58浏览次数:45  
标签:15 nLineStart void 模式 public Template Method


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

 

主要内容

1.概述

2.Template Method解说

3..NET中的Template Method模式

4.适用性及实现要点

 

概述

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

意图

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

结构图

第15章 模版方法模式(Template Method)_dataset

图1  Template Method 模式结构图

 

生活中的例子

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

第15章 模版方法模式(Template Method)_设计模式_02

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

Template Method模式解说

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

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

1.连接数据库(Connect)

2.执行查询命令(Select)

3.显示数据(Display)

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

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

第15章 模版方法模式(Template Method)_算法_03

图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()这两个抽象方法则留给具体的子类去实现,如下图:

第15章 模版方法模式(Template Method)_算法_04

图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模版方法模式(结构型模式)》


作者: TerryLee

标签:15,nLineStart,void,模式,public,Template,Method
From: https://blog.51cto.com/u_130277/6457544

相关文章

  • CMU15445 (Fall 2020) 数据库系统 Project#2 - B+ Tree 详解(上篇)
    前言考虑到B+树较为复杂,CMU15-445将B+树实验拆成了两部分,这篇博客将介绍Checkpoint#1部分的实现过程,搭配教材《DataBaseSystemConcepts》食用更佳。B+树索引许多查询只涉及文件中的少量记录,例如“找出物理系所有教师”的查询就只涉及教师记录中的一小部分,如果数据库......
  • 9.15 泛型通配符
    demo1“<?>“classMessage<T>{//定义泛型类对象privateTcontent;//泛型属性publicvoidsetContent(Tcontent){this.content=content;}publicTgetContent(){returnthis.content;}}publicclassHelloWorld{......
  • 看看Angular有啥新玩法!手把手教你在Angular15中集成Excel报表插件
    Angular15新特性Angular框架(以下简称“Angular”)作为一款由谷歌开发的Web应用程序框架,其强大的依赖注入系统、可重复使用的模块化开发理念和响应式编程模式等特点让Angular一问世便取得了巨大的关注和流量。截止目前为止,Angular已经迭代了15个版本,而Angular15又有哪些新的亮眼表现......
  • 物理备库在切换为主库时报错ORA-01577—主库已切换为备库
    问题描述:物理备库在切换为主库时报错ORA-01577,如下所示:数据库:oracle11.2.0.4系统架构:rac(2节点)+dg1、异常重现SYS@orcldg>alterdatabasecommittoswitchovertoprimarywithsessionshutdown;alterdatabasecommittoswitchovertoprimarywithsessionshutdown*......
  • 4.15学习总结
    androidstdio中marqueeRepeatLimit无法循环播放 首先,这个控件需要得到焦点,因此来实现循环播放,因此我们要 等我们再次启动虚拟机时,我们能够发现再次点击文字,就能够使控件文字循环播放。 但是这样点击文字循环会让整个页面看起来很傻逼,弄得就好像我们故意跟它显摆似的,......
  • 2023冲刺国赛模拟 15.1
    T1计数首先考虑计数有标号可重叠的方案数,容易发现此时\(x,y\)两维独立,因此考虑其中\(1\)维,设\(f_{i,j}\)表示此时考虑到第\(i\)对左右边界\((x_{i,1},x_{i,2})\),离散化后的\(x\)坐标形成了\(j\)个点时的方案数,容易发现此时数轴上存在\(j\)个点,以及\(j+1\)个空......
  • 算法刷题记录:P1518 [USACO2.4]两只塔姆沃斯牛 The Tamworth Two
    题目链接:https://www.luogu.com.cn/problem/P1518题目分析这道模拟题很典型了,给定了一个固定的移动方式,去模拟即可,该题说:如果牛和农夫永远不会相遇输出0,我没想到很好的方法,不推荐我这样的写法。算勉强AC吧。AC代码//Problem:P1518[USACO2.4]两只塔姆沃斯牛TheTamwort......
  • Luogu P4159 [SCOI2009] 迷路
    [SCOI2009]迷路题目背景windy在有向图中迷路了。题目描述该有向图有\(n\)个节点,节点从\(1\)至\(n\)编号,windy从节点\(1\)出发,他必须恰好在\(t\)时刻到达节点\(n\)。现在给出该有向图,你能告诉windy总共有多少种不同的路径吗?答案对\(2009\)取模。注意:windy......
  • P4159 [SCOI2009] 迷路
    目录题目链接题目内容前置知识:矩阵快速幂思路历程1.我寻思这图里咋还有自环呢2.ok快乐的板子时光总是短暂的()3.额我们还是不看边权,但是不扯到图上去了。4.那我们现在加上边权吧5.回归本题代码实现:题目链接题目内容[SCOI2009]迷路题目背景windy在有向图中迷路了。题目描述......
  • RedmiBook Pro 15 2022 锐龙版 安装ubuntu,没有WiFi解决方案
    一、原因ubuntu没有对应的网卡驱动二、解决方案1.换源为了之后的安装软件因此要换成快速的国内镜像源,此处推荐清华源备份原来的source.list文件命令,并打开文件编辑cd/etc/apt/sudocpsources.listsources.list.baksudogeditsources.list将清华源中内容复制到......