那么,我正在通过this关于“基类使用”MSDN的优秀文章。虽然我理解基类和接口的概念,但我无法理解本文第二段中的Template方法的用法(“受保护的方法和构造函数”)。模板方法在基类中的用法是什么?
任何人都可以通过一个简单的实际例子帮助我理解这个概念吗?也许,理解模板方法的概念是一个很好的开始。
在此先感谢。
那么,我正在通过this关于“基类使用”MSDN的优秀文章。虽然我理解基类和接口的概念,但我无法理解本文第二段中的Template方法的用法(“受保护的方法和构造函数”)。模板方法在基类中的用法是什么?
任何人都可以通过一个简单的实际例子帮助我理解这个概念吗?也许,理解模板方法的概念是一个很好的开始。
在此先感谢。
这在我看来是很老的文章,不记得看到有默认地将Impl命名。
我认为维基百科有更好的描述:
模板方法用于:
让子类实现(通过方法重载的)行为,可以在代码中改变
避免重复:一般工作流结构在抽象类的算法中实现一次,并且在每个子类中实现必要的变化。
控制在什么点允许子类化。与简单的多态覆盖相反,基本方法将被完全重写,允许根本改变工作流程,只允许改变工作流程的具体细节。
的控制结构(控制反转),这是一个模板模式的应用的结果往往是被称为好莱坞原则:“不要给我们打电话,我们会打电话给你。”使用此原则,父类中的模板方法通过根据需要调用子类方法来控制整个过程。
简而言之,您可以在基类中定义骨架,派生类实现实现之间的差异。
比方说,我们有信息,必须发布到不同的渠道。
因此,我们制作基类的Publisher,它有骨架如何做到这一点。
我们强制执行初始化,即每个派生都会设置地址在哪里发布。
我们使发送实现,适合大多数渠道,如果某些渠道使用ftp而不是http,我们让重写发送。
并且记录到数据库所做的操作对于所有通道都是一样的,所以我们不会重写。
只有发布才会对发布者指派的类的用户有用,因此只有该方法是公共的。
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)
}
}
这个想法是,你有一个方法的多重公共重载,所有方法都在内部使用单一方法。因此,没有任何公共重载实现本身。相反,受保护的方法用于所有重载的实际实现。
所以首先,你不要重复自己,因为你只有一次实现,所有带有默认值的重载只需通过设置一些默认值来调用实现。
现在,当继承类时,派生类可以简单地覆盖内部实现,一旦和所有以前的公共重载将立即使用新的实现。因此,您可以使用标准实现在基类中指定公共接口,但允许派生类在遵守接口合同的同时更改该实现。
现在人们可能会争论为什么实施被放在一个单独的方法,我真的不知道。相反,人们可以轻松实现方法的最通用签名,并简单地使其他方法调用该方法而不是内部方法。一个单独的方法的原因可能是你可以添加公共方法不可见的内部使用参数,但我想这取决于你想要做什么。
Thanks !,在这种特殊情况下,信息是否隐藏驱动因素将实施与公共方法分开。 (除了保持结构/工作流程相同。)如果我理解正确,那么我认为它是一个非常好的编程结构。现在我想知道使用这种模式有什么缺点。 – Aakash
您可以搜索模板方法设计模式。该模式包括一个Template方法,它提供了一个框架调用方法序列。一个或多个步骤可以推迟到实现这些步骤的子类,而不改变整个调用序列。例如:
// 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()");
}
}
}
谢谢Giedrius,这是一个非常丰富的例子。我想我现在对这个概念有了一些了解。但我不知道是否值得深入研究,或者是否有人在实际应用中使用这种风格。 – Aakash
命名风格 - 不,但模式被使用,有用和相当自然(自然 - 我的意思是我使用它时,不知道这是一个众所周知的模式:)。 – Giedrius
:-)也许我没注意到。虽然它简单而整洁。感谢你的帮助。 – Aakash