理解和实现 C# 中的模板方法设计模式






4.87/5 (20投票s)
引言
本文讨论了模板方法设计模式,这种模式在什么时候有用,以及我们可以从中获得什么好处。本文还展示了 C# 中模板设计模式的一个基本实现。
背景
在我们的应用程序中,有些场景我们需要执行某些活动,但执行该任务的算法可能有所不同。 这种场景可以使用策略模式进行设计,以便执行操作的基本代码保持不变,并且执行任务的算法可以动态切换。 有关策略模式的详细信息,请参阅:在 C# 和 C++ 中理解和实现策略模式[^]
现在可能有一些场景,执行任务的实际算法将保持不变,但从实现的角度来看,该算法的某些步骤可能有所不同。 由于在这些场景中算法相同,因此实现策略模式对其来说会显得过分。 在这种情况下,我们可以做的是使用继承的力量来实现这一点(而不是策略模式提供的组合)。
模板方法模式在这种场景中很有用,即存在一个算法,而该算法的某些小部分可能会发生变化。 GoF 将模板方法模式定义为“在操作中定义算法的骨架,将某些步骤推迟到子类。 模板方法允许子类重新定义算法的某些步骤,而无需更改算法的结构。”。

在上面显示的类图中
AbstractClass
:此类主要包含 2 种方法。 首先,它包含算法每个步骤的方法。此类中的第二种方法是模板方法。 模板方法是使用所有单个方法并为算法的执行提供框架的方法。ConcreteClass
:此类包含覆盖 Abstract 类为算法每个步骤提供的方法。它们包含这些步骤的自定义实现。此类将包含这些步骤的默认实现。
使用代码
现在让我们尝试看一下这种模式在 C# 中的一个示例实现。 假设我们有一个类,该类从数据源读取数据,然后创建一个用于 MIS 报告的文件。
abstract class DataExporter
{
// This will not vary as the data is read from sql only
public void ReadData()
{
Console.WriteLine("Reading the data from SqlServer");
}
// This will not vary as the format of report is fixed.
public void FormatData()
{
Console.WriteLine("Formating the data as per requriements.");
}
// This may vary based on target file type choosen
public abstract void ExportData();
// This is the template method that the client will use.
public void ExportFormatedData()
{
this.ReadData();
this.FormatData();
this.ExportData();
}
}
ReadData
和 FormatData
的实现将不会根据需求而改变。唯一可更改的部分是 ExportData
函数,其实现将根据要导出到的目标文件而改变。 因此,如果我们需要将数据导出到 Excel 文件,我们需要一个 ConcreteClass
来实现。
class ExcelExporter : DataExporter
{
public override void ExportData()
{
Console.WriteLine("Exporting the data to an Excel file.");
}
}
类似地,如果我们需要将数据导出到 PDF 文件,我们将需要另一个具体类来覆盖算法的导出部分。
class PDFExporter : DataExporter
{
public override void ExportData()
{
Console.WriteLine("Exporting the data to a PDF file.");
}
}
现在的好处是应用程序将使用 DataExporter
类,并且算法的所需实现将从派生类中获取。
static void Main(string[] args)
{
DataExporter exporter = null;
// Lets export the data to Excel file
exporter = new ExcelExporter();
exporter.ExportFormatedData();
Console.WriteLine();
// Lets export the data to PDF file
exporter = new PDFExporter();
exporter.ExportFormatedData();
}

因此,我们已经看到导出数据的实际算法保持不变,但将要导出的文件类型部分可以移动到派生类中。 模板方法将对实现一无所知,并且将运行算法。 在运行时,它将调用派生类覆盖的函数来执行所需的功能。
在结束之前,让我们看一下我们的虚拟应用程序的类图,并将其与模板方法模式的类图进行比较。

关注点
在本文中,我们试图了解为什么以及何时我们可能会发现模板方法模式有用。 我们还看到了 C# 中模板方法模式的一个基本实现。 模板方法模式是好莱坞原则的一个很好的例子,即“不要打电话给我们,我们会给你打电话”,这样模板方法将始终对实际实现一无所知,但每当需要时,它将调用子类来获取所需的功能。 我希望这篇小文章信息量很大。
历史
- 2012 年 10 月 23 日: 第一个版本。