设计模式之template method模版方法模式


意图intent:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

适用性:

  • 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
  • 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是OpdykeJohnson所描述过的重分解以一般化的一个很好的例子[OJ93]。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
  • 控制子类扩展。模板方法只在特定点调用“hook”操作(参见效果一节),这样就只允许在这些点进行扩展。

Definition

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.

 

participants

    The classes and/or objects participating in this pattern are:

  • AbstractClass  (DataObject)
    • defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm
    • implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects.
  • ConcreteClass  (CustomerDataObject)
    • implements the primitive operations ot carry out subclass-specific steps of the algorithm

Template method模版方法模式,主要就是把父类的一些方法deferred to子类去实现,这样子类就有更多的空间来改变了,其实也是挺简单的,呵呵。不同的子类就有不同的具体实现了。有人说“如果你只想掌握一种设计模式,那么它就是template method了”,因为template method实在是太简单了,所以它是那样的无处不在阿。

 

Sample code in c#

This structural code demonstrates the Template method which provides a skeleton calling sequence of methods. One or more steps can be deferred to subclasses which implement these steps without changing the overall calling sequence.

// Template Method pattern -- Structural example

 

using System;

namespace DoFactory.GangOfFour.Template.Structural
{
  
  // MainApp test application

  class MainApp
  {
    static void Main()
    {
      AbstractClass c;
      
      c = new ConcreteClassA();
      c.TemplateMethod();

      c = new ConcreteClassB();
      c.TemplateMethod();

      // Wait for user
      Console.Read();
    }
  }

  // "AbstractClass"

  abstract class AbstractClass
  {
    public abstract void PrimitiveOperation1();
    public abstract void PrimitiveOperation2();

    // The "Template method"
    public void TemplateMethod()
    {
      PrimitiveOperation1();
      PrimitiveOperation2();
      Console.WriteLine("");
    }
  }

  // "ConcreteClass"

  class ConcreteClassA : AbstractClass
  {
    public override void PrimitiveOperation1()
    {
      Console.WriteLine("ConcreteClassA.PrimitiveOperation1()");
    }
    public override void PrimitiveOperation2()
    {
      Console.WriteLine("ConcreteClassA.PrimitiveOperation2()");
    }
  }

  class ConcreteClassB : AbstractClass
  {
    public override void PrimitiveOperation1()
    {
      Console.WriteLine("ConcreteClassB.PrimitiveOperation1()");
    }
    public override void PrimitiveOperation2()
    {
      Console.WriteLine("ConcreteClassB.PrimitiveOperation2()");
    }
  }
}

 

Output

ConcreteClassA.PrimitiveOperation1()

ConcreteClassA.PrimitiveOperation2()

 

ConcreteClassB.PrimitiveOperation1()

ConcreteClassB.PrimitiveOperation2()

 

This real-world code demonstrates a Template method named Run() which provides a skeleton calling sequence of methods. Implementation of these steps are deferred to the CustomerDataObject subclass which implements the Connect, Select, Process, and Disconnect methods.

// Template Method pattern -- Real World example

 

using System;
using System.Data;
using System.Data.OleDb;

namespace DoFactory.GangOfFour.Template.RealWorld
{
  
  // MainApp test application

  class MainApp
  {
    static void Main()
    {
      DataAccessObject dao;
      
      dao = new Categories();
      dao.Run();

      dao = new Products();
      dao.Run();

      // Wait for user
      Console.Read();
    }
  }

  // "AbstractClass"

  abstract class DataAccessObject
  {
    protected string connectionString;

    protected DataSet dataSet;

    public virtual void Connect()
    {
      // Make sure mdb is on c:/
      connectionString =
        "provider=Microsoft.JET.OLEDB.4.0; " +
        "data source=c://nwind.mdb";
    }

    public abstract void Select();
    public abstract void Process();

    public virtual void Disconnect()
    {
      connectionString = "";
    }

    // The "Template Method"

    public void Run()
    {
      Connect();
      Select();
      Process();
      Disconnect();
    }
  }

  // "ConcreteClass"

  class Categories : DataAccessObject
  {
    public override void Select()
    {
      string sql = "select CategoryName from Categories";
      OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
        sql, connectionString);

      dataSet = new DataSet();
      dataAdapter.Fill(dataSet, "Categories");
    }

    public override void Process()
    {
      Console.WriteLine("Categories ---- ");
      
      DataTable dataTable = dataSet.Tables["Categories"];
      foreach (DataRow row in dataTable.Rows)
      {
        Console.WriteLine(row["CategoryName"]);
      }
      Console.WriteLine();
    }
  }

  class Products : DataAccessObject
  {
    public override void Select()
    {
      string sql = "select ProductName from Products";
      OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
        sql, connectionString);

      dataSet = new DataSet();
      dataAdapter.Fill(dataSet, "Products");
    }

    public override void Process()
    {
      Console.WriteLine("Products ---- ");
      DataTable dataTable = dataSet.Tables["Products"];
      foreach (DataRow row in dataTable.Rows)
      {
        Console.WriteLine(row["ProductName"]);
      }
      Console.WriteLine();
    }
  }
}

 

Output

Categories ----

Beverages

Condiments

Confections

Dairy Products

Grains/Cereals

Meat/Poultry

Produce

Seafood

 

Products ----

Chai

Chang

Aniseed Syrup

Chef Anton's Cajun Seasoning

Chef Anton's Gumbo Mix

Grandma's Boysenberry Spread

Uncle Bob's Organic Dried Pears

Northwoods Cranberry Sauce

Mishi Kobe Niku

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值