模板方法模式(TemplateMethod):定義一個操作中的算法的骨架,而將一些步驟延遲到子類。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
UML類圖:
TemplateClass是抽象類,其實也就是一個抽象模板,定義並實現一個模板方法,這個模板方法一般是一個具體的方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類實現,頂級邏輯也有可能調用一些具體方法;
ConcreteClass實現父類所定義的一個或者多個抽象方法,每一個TemplateClass都可以有任意多個ConcreteClass與之對應,而每一個ConcreteClass都可以給出這些抽象方法(也就是頂級邏輯的組成步驟)的不同實現,從而使得頂級邏輯的實現各不相同;
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TemplateMethod
{
/*
* 模板類是一個抽象類,定義並實現了一個模板方法,定義了算法的骨架,具體子類
* 將重定義PrimitiveOperation以實現一個算法的步驟
*/
abstract class TemplateClass
{
public void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
}
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
}
/*
* ConcreteClass實現父類所定義的一個活多個抽象方法,每一個TemplateClass都可以有
* 任意多個ConcreteClass與之對應,因而每個ConcreteClass都可以給出這些抽象方法(也
* 就是頂級邏輯的組成步驟)的不同實現,從而使得頂級邏輯的實現各不相同
*/
class ConcreteClassA : TemplateClass
{
public override void PrimitiveOperation1()
{
Console.WriteLine("具體類A的PrimitiveOperation1的方法實現...");
//throw new NotImplementedException();
}
public override void PrimitiveOperation2()
{
Console.WriteLine("具體類A的PrimitiveOperation2的方法實現...");
//throw new NotImplementedException();
}
}
class ConcreteClassB : TemplateClass
{
public override void PrimitiveOperation1()
{
Console.WriteLine("具體類B的PrimitiveOperation1的方法實現...");
//throw new NotImplementedException();
}
public override void PrimitiveOperation2()
{
Console.WriteLine("具體類B的PrimitiveOperation2的方法實現...");
//throw new NotImplementedException();
}
}
}
客戶端調用:
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TemplateMethod
{
class Program
{
static void Main(string[] args)
{
TemplateClass tc;
tc = new ConcreteClassA();
tc.TemplateMethod();
tc = new ConcreteClassB();
tc.TemplateMethod();
Console.Read();
}
}
}
模板方法模式特點:模板方法模式是通過把不變行為搬移到子類,去除子類中的重復代碼來體現它的優勢。也就是說模板方法模式就是提供了一個很好的代碼復用平台,因為有時候,我們會遇到一系列步驟構成的過程需要執行。這個過程從層次上看是相同的,但有些步驟的實現可能不同,這時候通常就考慮使用模板方法模式。
碰到這個情況,當不變的和可變的行為在方法的子類實現中混合在一起的時候,不變的行為就會在子類中重復出現,我們通過模板方法模式把這些行為搬移到單一的地方,這樣就幫助子類擺脫重復的不變行為的糾纏。
模板方法模式是一個很常用的模式,對繼承和多態有很大幫助,比如在.NET或java類庫的設計中,通常都會利用模板方法模式提取類庫中的公共行為到抽象類中。
下面描述一個模板方法模式的一個應用案例,有助於該設計模式的理解與運用。
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TemplateMethodExample
{
/*
* 試卷類是一個抽象類
*/
abstract class TestPaper
{
private string sName;//學生姓名
private string sNo; //學生學號
public TestPaper()
{
this.sName = "";
this.sNo = "";
}
public string getSName()
{
return this.sName;
}
public void setSName(string name)
{
this.sName = name;
}
public string getSNo()
{
return this.sNo;
}
public void setSNo(string no)
{
this.sNo = no;
}
public void answerQuestion1()
{
Console.Write(" 問題1... ");
Console.WriteLine(/*"姓名:"+ this.getSName() +"學號:"+ this.getSNo() + */" 答案:" + answer1());
}
public void answerQuestion2()
{
Console.Write(" 問題2... ");
Console.WriteLine(/*"姓名:"+ this.getSName() +"學號:"+ this.getSNo() + */" 答案:" + answer2());
}
public void answerQuestion3()
{
Console.Write(" 問題3... ");
Console.WriteLine(/*"姓名:"+ this.getSName() +"學號:"+ this.getSNo() + */" 答案:" + answer3());
}
protected abstract string answer1();
protected virtual string answer2()
{
return "";
}
protected virtual string answer3()
{
return "";
}
}
/*
* 具體的子類,實現父類中的虛方法
*/
class TestPaper_StudentA : TestPaper
{
public TestPaper_StudentA(string name, string no)
{
this.setSName(name);
this.setSNo(no);
}
protected override string answer1()
{
return "A";
}
protected override string answer2()
{
return "B";
}
protected override string answer3()
{
return "C";
}
}
class TestPaper_StudentB : TestPaper
{
public TestPaper_StudentB(string name, string no)
{
this.setSName(name);
this.setSNo(no);
}
protected override string answer1()
{
return "A";
}
protected override string answer2()
{
return "B";
}
protected override string answer3()
{
return "C";
}
}
}
客戶端:
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TemplateMethodExample
{
class Program
{
static void Main(string[] args)
{
TestPaper tpA = new TestPaper_StudentA("lucy","1001");
Console.WriteLine("姓名:"+tpA.getSName()+"學號:"+tpA.getSNo());
tpA.answerQuestion1();
tpA.answerQuestion2();
tpA.answerQuestion3();
TestPaper tpB = new TestPaper_StudentB("Tom","1002");
Console.WriteLine("姓名:" + tpB.getSName() + "學號:" + tpB.getSNo());
tpB.answerQuestion1();
tpB.answerQuestion2();
tpB.answerQuestion3();
Console.Read();
}
}
}
運行結果:
該例中,TestPaper是抽象模板類,TestPaper_StudentA、TestPaper_StudentB為其子類,實現其抽象方法。