好吧,我正在阅读MSDN 上这篇关于“基类用法”的优秀文章。虽然我了解基类和接口的概念,但我无法理解本文第二段(“受保护的方法和构造函数”)中模板方法的用法。
任何人都可以通过一个简单的实际示例帮助我理解这个概念吗?也许,了解模板方法的概念是一个很好的起点。
提前致谢。
好吧,我正在阅读MSDN 上这篇关于“基类用法”的优秀文章。虽然我了解基类和接口的概念,但我无法理解本文第二段(“受保护的方法和构造函数”)中模板方法的用法。
任何人都可以通过一个简单的实际示例帮助我理解这个概念吗?也许,了解模板方法的概念是一个很好的起点。
提前致谢。
在我看来,那是一篇很老的文章,不记得看到用 Impl 命名。
我认为维基百科有更好
的描述:模板方法用于:
让子类实现(通过方法覆盖)可以变化的行为
避免代码重复:一般工作流结构在抽象类的算法中实现一次,在每个子类中实现必要的变化。
控制在什么时候允许子类化。与简单的多态覆盖相反,其中基本方法将被完全重写,从而允许对工作流进行彻底更改,只允许更改工作流的特定细节。
作为应用模板模式的结果的控制结构(控制反转)通常被称为好莱坞原则:“不要打电话给我们,我们会打电话给你。” 利用这个原理,父类中的模板方法根据需要调用子类方法来控制整个流程。
简而言之,您在基类中定义骨架,而派生类实现实现之间的差异。
假设我们有信息,必须发布到不同的渠道。
所以我们创建了基类 Publisher,它具有如何做到这一点的骨架。
我们强制实现初始化,每个派生都会设置发布地址。
我们制作了适合大多数通道的发送实现,如果某些通道使用 ftp 而不是 http,我们让覆盖发送。
并且将所有通道的日志记录到 dababase 是相同的,因此我们不允许覆盖它。
只有发布对 Publisher 派生类的用户感兴趣,所以只有该方法是公共的。
public abstract class Publisher
{
private address;
// if you wish to force implementation in derived class, make method abstract
private abstract void Initialize();
// if you wish optional implementation in derived class, make it virtual
protected virtual void SendChangesToWeb()
{
// ...
webClient.Upload(address, data)
}
// if you wish that some step could not be changed from outside
private void LogSentChangesToDatabase()
{
// ... save date time when was send and what was sent
}
// this sequence is the same for all derives, no point to duplicate
public void PublishUpdates()
{
Initialize();
SendChangesToWeb();
LogSentChangesToDatabase();
}
}
public class GooglePublisher : Publisher {
private override Initialize()
{
address = "http://www.google.com";
}
}
public class FtpPublisher : Publisher {
private override Initialize()
{
address = "ftp://test.com";
}
protected override SendChangesToWeb()
{
FtpClient.Upload(address, data)
}
}
这个想法是你有一个方法的多个公共重载,它们都在内部使用一个方法。因此,没有一个公共重载本身具有实现。相反,受保护的方法用于所有重载的实际实现。
因此,首先,您不要重复自己,因为您只有一次实现,所有具有默认值的重载只需通过设置一些默认值来调用实现。
现在在继承类时,派生类可以简单地覆盖内部实现一次,所有以前的公共重载将立即使用新的实现。因此,您可以使用标准实现在基类中指定公共接口,但允许派生类在遵守接口约定的同时更改该实现。
现在有人可能会争论为什么将实现放在一个单独的方法中,我真的不知道。相反,人们可以轻松地实现一个方法的最通用签名,并简单地让其他方法调用该方法而不是内部方法。使用单独方法的原因可能是您可以添加公共方法不可见的内部使用参数,但我想这取决于您想要做什么。
您可以搜索模板方法设计模式。这个模式包括一个模板方法,它提供了一个框架调用序列的方法。一个或多个步骤可以推迟到实现这些步骤的子类,而不改变整个调用顺序。例子:
// Template Method pattern -- Structural example
using System;
namespace DoFactory.GangOfFour.Template.Structural
{
/// <summary>
/// MainApp startup class for Real-World
/// Template Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
AbstractClass aA = new ConcreteClassA();
aA.TemplateMethod();
AbstractClass aB = new ConcreteClassB();
aB.TemplateMethod();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'AbstractClass' abstract class
/// </summary>
abstract class AbstractClass
{
public abstract void PrimitiveOperation1();
public abstract void PrimitiveOperation2();
// The "Template method"
public void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
Console.WriteLine("");
}
}
/// <summary>
/// A 'ConcreteClass' class
/// </summary>
class ConcreteClassA : AbstractClass
{
public override void PrimitiveOperation1()
{
Console.WriteLine("ConcreteClassA.PrimitiveOperation1()");
}
public override void PrimitiveOperation2()
{
Console.WriteLine("ConcreteClassA.PrimitiveOperation2()");
}
}
/// <summary>
/// A 'ConcreteClass' class
/// </summary>
class ConcreteClassB : AbstractClass
{
public override void PrimitiveOperation1()
{
Console.WriteLine("ConcreteClassB.PrimitiveOperation1()");
}
public override void PrimitiveOperation2()
{
Console.WriteLine("ConcreteClassB.PrimitiveOperation2()");
}
}
}
参考:模板方法设计模式