C# 模板方法在基类中有什么用途?
嗯,我正在阅读MSDN上关于“基类用法”的优秀文章。虽然我理解基类和接口的概念,但我无法理解本文第二段(“受保护的方法和构造函数”)中模板方法的用法 有人能帮我通过一个简单的实例来理解这个概念吗?也许,理解模板方法的概念是一个很好的起点C# 模板方法在基类中有什么用途?,c#,base-class,template-method-pattern,C#,Base Class,Template Method Pattern,嗯,我正在阅读MSDN上关于“基类用法”的优秀文章。虽然我理解基类和接口的概念,但我无法理解本文第二段(“受保护的方法和构造函数”)中模板方法的用法 有人能帮我通过一个简单的实例来理解这个概念吗?也许,理解模板方法的概念是一个很好的起点 提前感谢。我们的想法是,一个方法有多个公共重载,所有重载在内部都使用一个方法。因此,没有一个公共重载具有实现本身。相反,所有重载的实际实现都使用受保护的方法 因此,首先,您不要重复自己的操作,因为您只有一次实现,所有带有默认值的重载只需通过设置一些默认值来调用实
提前感谢。我们的想法是,一个方法有多个公共重载,所有重载在内部都使用一个方法。因此,没有一个公共重载具有实现本身。相反,所有重载的实际实现都使用受保护的方法 因此,首先,您不要重复自己的操作,因为您只有一次实现,所有带有默认值的重载只需通过设置一些默认值来调用实现 现在,当继承该类时,派生类只需重写内部实现一次,所有以前的公共重载都将立即使用新的实现。因此,您可以使用标准实现在基类中指定公共接口,但允许派生类在遵守接口约定的同时更改该实现
现在有人可能会争论为什么要将实现放在一个单独的方法中,我真的不知道。相反,我们可以轻松地实现一个方法的最通用的签名,并简单地让其他方法调用该方法而不是内部方法。使用单独方法的原因可能是您可以添加公共方法看不到的内部使用参数,但我想这取决于您想做什么。您可以搜索模板方法设计模式。这个模式包括一个模板方法,它提供了一个方法的骨架调用序列。一个或多个步骤可以推迟到实现这些步骤的子类,而不改变整个调用序列。例如:
// 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()");
}
}
}
//模板方法模式——结构示例
使用制度;
命名空间DoFactory.GangOfFour.Template.Structural
{
///
///适用于真实世界的MainApp启动类
///模板设计模式。
///
类MainApp
{
///
///进入控制台应用程序的入口点。
///
静态void Main()
{
AbstractClass aA=新的ConcreteClassA();
aA.TemplateMethod();
AbstractClass aB=新的ConcreteClassB();
aB.TemplateMethod();
//等待用户
Console.ReadKey();
}
}
///
///“AbstractClass”抽象类
///
抽象类抽象类
{
公共抽象void PrimitiveOperation1();
公共抽象void原语操作2();
//“模板法”
公共void TemplateMethod()
{
基本操作1();
基本操作2();
控制台。写线(“”);
}
}
///
///“具体类”类
///
类ConcreteClassA:抽象类
{
公共覆盖无效原语操作1()
{
Console.WriteLine(“ConcreteClassA.PrimitiveOperation1()”;
}
公共覆盖无效原语操作2()
{
Console.WriteLine(“ConcreteClassA.PrimitiveOperation2()”;
}
}
///
///“具体类”类
///
类ConcreteClassB:抽象类
{
公共覆盖无效原语操作1()
{
Console.WriteLine(“ConcreteClassB.PrimitiveOperation1()”;
}
公共覆盖无效原语操作2()
{
Console.WriteLine(“ConcreteClassB.PrimitiveOperation2()”;
}
}
}
参考资料:在我看来,这是一篇非常古老的文章,我不记得看到过使用Impl命名 我认为维基百科有更好的描述:
模板方法用于:
- 让子类实现(通过方法重写)可以变化的行为
- 避免代码中的重复:一般工作流结构在抽象类的算法中实现一次,并且在每个子类中实现必要的变化
- 控制允许子类化的点。与简单的多态覆盖(基本方法将被完全重写,从而允许对工作流进行根本性更改)相反,只允许更改工作流的特定细节
所以我们制作了基类发布器,它有一个框架如何做到这一点。
我们强制实现初始化,每个派生将设置发布地址。
我们实现了发送,这适合大多数通道,如果某些通道使用ftp而不是http,我们允许覆盖发送。
所有频道的登录操作都是相同的,因此我们不允许覆盖它。
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)
}
}
谢谢在这种特殊情况下,隐藏信息是将实现与公共方法分离的驱动因素。(除了保持结构/工作流程不变)如果我理解正确,那么我认为这是一个非常好的编程结构。现在我想知道使用这种模式的缺点是什么。谢谢Giedrius,这是一个非常有用的例子。我想我现在真的对这个概念有了一些了解。但我不知道是否值得深入研究