设计模式系列之Template Method(模板方法模式)

     在面向对象设计中,无非就是封装,继承之类的运用,而设计出可扩展性好,代码冗余少,可重用性高的程序也是衡量面向对象开发的一个标准。面向对象使用至关灵活,虽然核心特征只有封装,继承,多态,可是经过对它们的灵活配合和使用变化出了各类设计模式。能够说,设计模式是对面向对象的一些经验总结,今天将看到其中的一个,Template Method(模板方法模式)。算法

 

Template Method(模板方法模式) 

 

    定义:定义一个操做中的算法的骨架,而将一些步骤延迟到子类中。Te m p l a t e M e t h o d使得子类设计模式

能够不改变一个算法的结构便可重定义该算法的某些特定步骤。 (摘自:《设计模式:可复用面向对象软件的基础》)ide

 

    那么如何来理解上述的定义呢?能够这样想,模板方法,说到底也是一个方法,而它的做用正如其名--模板。在这个模板里面,定义了一系列连续的动做。这样,当调用这个模板方法后,其内部的方法将被按照顺序调用。可是,仅此而已的话,只是对一系列方法进行了封装,根本没有体现面向对象,其关键在定义的后半句,将一些步骤延迟到子类中。模板方法为了减小代码冗余,将子类中相同的操做提取出来,放到抽象父类中,这些方法咱们叫作具体方法(Concrete Method),而若是是不一样的操做的话,就在抽象类中定义它们的抽象方法(Abstract Method),把具体的实现延迟到子类中去。除此以外,在抽象父类中还有一类方法,这类方法在须要的时候,能够在子类中实现它们,与抽象方法不一样的是在子类中比较自由,没有强制性要求实现,此类方法叫作钩子方法(HookMethod),为了区别抽象方法,在定义时通常以Do开头,例如DoCloseDocument();上述三类方法都将被放到模板方法中(Template Method)。这样,在客户端中,咱们调用模板方法,模板方法调用将是不变的,由于在模板方法中的算法结构是固定不变的,可是能够经过实现不一样的子类方法,重定义算法的某些特定步骤。spa

 
     上述描述的有点多,看着晕了,仍是以一个简单的例子再来理解下:设计

 

如何把大象放进冰箱 

 

      记得这是赵本山好久之前的一个小品《钟点工》里的一个例子,虽然当年这个节目的时候,我年纪还很小,可是居然还印象深入。这里,就用这个例子来演示模板方法模式。对象


1、分析此过程继承

 经过此例子,咱们知道,把大象放进冰箱,须要三步(不考虑冰箱中是否有长颈鹿或者冰箱已经满了,咱们忽略这些):ci

 

1.打开冰箱开发

2.把大象放进去string

3.关上冰箱

 

2、抽象出更抽象的过程

 

    能够放大象,固然能够放其它东西,好比放小鸡,放长颈鹿等等,全部的这些东西咱们就叫东西,这话听怎么这么奇怪,那就书面化点,全部的这些东西咱们叫作对象。

这样,抽象出的一个基类能够叫作:Abstract class PutSomethingIntoFridge{}

 而后,在基类中咱们把东西放进冰箱的一系列算法步骤写入Put()的模板方法中。

而后....此处省略100个字,具体看下文代码 

 

 3、继承父类,实现各类东西放进冰箱

 


设计完成后,整个结构以下图所示:

 

示例代码:

PutSomethingIntoFridge.cs

 

using   System;

 namespace   PatternDemo
{
    
 abstract     class   PutSomethingIntoFridge
    {
        
 //  模板方法  
           public     void   Put()
        {
            
 //  具体方法  
             OpenFridge();
            
 //  Hook方法,扩大冰箱容量  
             DoEnlargeCapacity();
            
 //  抽象方法  
             PutInto();
            
 //  具体方法  
             CloseFridge();
        
        }

        
 //  具体方法,无需在子类中从新实现  
           protected      void   OpenFridge()
        {
            Console.WriteLine(
 "  打开冰箱  "  );
        
        }

        
 //  具体方法,无需在子类中从新实现  
           protected     void   CloseFridge()
        {

            Console.WriteLine(
 "  关上冰箱  "  );
        
        }

        
 //  抽象方法,在子类中强制实现  
           abstract     protected     void   PutInto();

        
 //  Hook方法,扩大冰箱容量,此方法在子类中可选择实现。换句话说,只有在必要的时候才重写实现它  
          virtual     protected     void   DoEnlargeCapacity(){}

    }
}

 

 

 PutChickenIntoFridge.cs

using System;  
 namespace   PatternDemo
{
    
 class   PutChickenIntoFridge : PutSomethingIntoFridge
    {
        
 //  普通冰箱能放下一只鸡,固然是在冰箱没有满的状况下,因此只要实现具体放的东西方法就行  
           protected     override     void   PutInto()
        {
            Console.WriteLine(
 "  把鸡放进冰箱  "  );
        }
    }
}



PutElephantIntoFridge

using    System;

  namespace    PatternDemo
{
    
  class    PutElephantIntoFridge : PutSomethingIntoFridge
    {
        
  //   因为大象太大,普通冰箱没法放进去,须要扩大冰箱容量,因此实现DoEnlargeCapacity方法  
             protected       override       void    DoEnlargeCapacity()
        {
            Console.WriteLine(
  "   扩大冰箱容量10000倍   "   );
        }

        
  protected       override       void    PutInto()
        {
            Console.WriteLine(
  "   把大象放进冰箱   "   );
        }
    }
 


Client

namespace    PatternDemo
{
    
  class    Client
    {
        
  static       void    Main(   string   [] args)
        {
            PutSomethingIntoFridge putchicken 
  =       new    PutChickenIntoFridge();
            putchicken.Put();

            PutSomethingIntoFridge putelephant 
  =       new    PutElephantIntoFridge();
            putelephant.Put();
            
        }
    }
 



对与Template Method(模板方法)的一些总结

 


 模板方法是一种代码复用的基本技术,它们在类库中尤其重要,它们提取了类库中的公共行为。

 模板方法的适用状况:

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

• 各子类中公共的行为应被提取出来并集中到一个公共父类中以免代码重复。首先识别

现有代码中的不一样之处,而且将不一样之处分离为新的操做。最后,用一个调用这些新的

操做的模板方法来替换这些不一样的代码。

• 控制子类扩展。模板方法只在特定点调用“ h o o k”操做(例如这里举例的当冰箱装不下大象这样的特殊状况时),这样就只允

许在这些点进行扩展。

 

 须要注意的地方:

1.为了保证模板方法中调用的各类原语操做(抽象方法,具体方法,Hook方法)只能被模板方法调用,访问权限应为protected。

2.尽可能减小原语操做。以防客户端代码冗长。

3.避免乱用模板方法,致使子类泛滥,应根据具体状况适时的使用。

 

 参考资料

《设计模式:可复用面向对象软件的基础》