• 设计模式 行为型之王 模板方法模式


      “四人帮”23种设计模式可分为三大类:创建型,结构型,行为型。每种模式中都有一个最常用的模式,例如,创建型中最常用的是工厂方法模式,结构型模式中最常用的是适配器模式,行为型模式中最常用的是模板方法模式,本节重点讲解模板方法模式。

      模板方法模式是最简单的设计模式,起这样的一个名字听起来可能感觉很专业,其实只要大家写过面向对象,就一定熟悉这个模式。说的更简单一点,只要抽象基类中定义了一个受保护的Abastract方法,并提供一个公开的访问接口(供子类访问),然后让子类去重写这个抽象方法,就是模板方法模式最常见的应用。

      为什么要用到模板方法模式呢?我们知道,通常写代码的时候,通常一个方法里面会包含几个子方法,但是其中一个方法,在基类中并不知道它具体有什么用途,只能由子类去决定具体要做什么事情,但是在基类中,我们必须按照事情的先后顺序执行(事件1->事件2->事件3->事件4),才能符合正常流程,如下图:

     

    要执行的方法如下:

     1 /// <summary>
     2 /// schedule template
     3 /// </summary>
     4 abstract class Schedule
     5 {
     6     public void Execute()
     7     {
     8         ExecuteThings1();
     9         ExecuteThings2();
    10         ExecuteThings3();
    11         ExecuteThings4();
    12     }
    13 
    14     private void ExecuteThings1()
    15     {
    16         //execute the concrete thing for Things1
    17         //such as: Print something.
    18     }
    19 
    20     private void ExecuteThings3()
    21     {
    22         //execute the concrete thing for Things3
    23         //such as : access the database
    24     }
    25 
    26     private void ExecuteThings4()
    27     {
    28         //execute the concrete thing for Things4
    29         //write something to the EventViewer
    30     }
    31 
    32     private void ExecuteThings2()
    33     {
    34         //do nothing
    35     }
    36 }
    View Code

    可是ExecuteThings2()方法我们不知道要做什么,这时候怎么办呢,直接写成吧,等于写了一个空方法,啥也都执行,并且当子类要继续时也不能根据具体执行什么东东来重写这个方法,这个方法并不能在动态运行时有多种表现,不满足多态的特点。

    1         private void ExecuteThings2()
    2         {
    3             //do nothing
    4         }
    View Code

    为了达到子类按需定制,就是大家常说的“钩子”效果,可以首先将方法申明为virtual/abstract,以便子类重写,因为这个方法是一个抽象方法(空方法,什么也不做,等同于C++中的纯虚函数),所以将该方法申明为abstract抽象方法,为了便于子类重写,而不被外界访问,我们使用保护修饰符protected,达到钩子效果,代码如下:

     1 /// <summary>
     2 /// schedule template
     3 /// </summary>
     4 abstract class Schedule
     5 {
     6     public void Execute()
     7     {
     8         ExecuteThings1();
     9         ExecuteThings2();
    10         ExecuteThings3();
    11         ExecuteThings4();
    12     }
    13 
    14     private void ExecuteThings1()
    15     {
    16         //execute the concrete thing for Things1
    17         //such as: Print something.
    18     }
    19 
    20     private void ExecuteThings3()
    21     {
    22         //execute the concrete thing for Things3
    23         //such as : access the database
    24     }
    25 
    26     private void ExecuteThings4()
    27     {
    28         //execute the concrete thing for Things4
    29         //write something to the EventViewer
    30     }
    31 
    32     private void ExecuteThings2()
    33     {
    34         //call the hook
    35         DoExecuteThings2();
    36     }
    37 
    38     /// <summary>
    39     /// hook method, the sub inherited class will implement the details.
    40     /// </summary>
    41     protected abstract void DoExecuteThings2();
    42 
    43 }
    View Code

    于是,子类可以按需重写他自己想要执行的事情。

     1 class GroupASchedule : Schedule
     2 {
     3     protected override void DoExecuteThings2()
     4     {
     5         Console.WriteLine("{0} -> we will execute my plan for GroupA!", this.GetType().Name);
     6     }
     7 }
     8 
     9 class GroupBSchedule : Schedule
    10 {
    11     protected override void DoExecuteThings2()
    12     {
    13         Console.WriteLine("{0} -> we will execute my plan for GroupB!", this.GetType().Name);
    14     }
    15 }
    View Code

    从而,实现了想做的具体事情2。

    示例代码: YearlyArrangement.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Template
    {
        abstract class YearlyArrangement
        {
            protected virtual void Work()
            {
                Console.WriteLine("Most of the time, we are working!");
            }
    
            /// <summary>
            /// hook method
            /// sub-class should override this method
            /// </summary>
            protected abstract void MakeEntertainmentEveryYear();
    
            protected virtual void AwardPrize()
            {
                Console.WriteLine("At the end of each year, the company holds an award-prize ceremony!");
            }
    
            protected virtual void AttendAnnualMeeting()
            {
                Console.WriteLine("At the end of each year, the company holds an annual meeting!");
            }
    
            public void MakePlan()
            {
                Console.WriteLine("Year: {0}", this.GetType().Name.Replace("Year", string.Empty));
                Work();
                MakeEntertainmentEveryYear();
                AwardPrize();
                AttendAnnualMeeting();
                Console.WriteLine();
            }
        }
    }

    Year2013.cs:

    class Year2013 : YearlyArrangement
    {
        protected override void MakeEntertainmentEveryYear()
        {
            Console.WriteLine("Travelling to America!");
        }
    }

    Year2014.cs:

    class Year2014 : YearlyArrangement
    {
        protected override void MakeEntertainmentEveryYear()
        {
            Console.WriteLine("Travelling to Paris!");
        }
    }

    Year2015.cs:

    class Year2015 : YearlyArrangement
    {
        protected override void MakeEntertainmentEveryYear()
        {
            Console.WriteLine("Go to lenovo for learning!");
        }
    }

    主函数Program.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Template
    {
        class Program
        {
            static void Main(string[] args)
            {
                Test();
            }
    
            static void Test()
            {
                YearlyArrangement year = new Year2013();
                year.MakePlan();
    
                year = new Year2014();
                year.MakePlan();
    
                year = new Year2015();
                year.MakePlan();
                Console.ReadKey();
            }
        }
    }

    运行效果:

    源代码下载: https://capps.codeplex.com/releases/view/107754

    由于水平有限,难免有描述不够准确之处,欢迎大家指正。
     

  • 相关阅读:
    mysql 库,表,数据操作
    mysql 初识数据库
    MySQL 索引 视图 触发器 存储过程 函数
    MySQL 事物和数据库锁
    MySQL 约束和数据库设计
    MySQL 创建千万集数据
    MySQL 各种引擎
    求1,1,2,3,5,8,13 斐波那契数列第N个数的值
    WEB前端研发工程师编程能力成长之路(1)
    XML DOM
  • 原文地址:https://www.cnblogs.com/Bowl2008/p/template_method_design_patterns.html
Copyright © 2020-2023  润新知