基类中模板方法的用途是什么?

时间:2012-07-04 07:06:19

标签: c# base-class template-method-pattern

好吧,我在MSDN上阅读了关于“ Base Class Usage ”的this优秀文章。虽然我理解基类和接口的概念,但我无法理解本文第二段中模板方法的用法(“受保护的方法和构造函数”)。

有没有人可以借助一个简单的实际例子帮助我理解这个概念?也许,了解模板方法的概念是一个很好的起点。

提前致谢。

3 个答案:

答案 0 :(得分:2)

在我看来,这是一篇非常古老的文章,不记得看到与Impl的命名。

我认为维基百科有更好的描述:
模板方法用于:

  • 让子类实现(通过方法覆盖)可以改变的行为

  • 避免代码重复:一般工作流结构在抽象类的算法中实现一次,并在每个子类中实现必要的变体。

  • 控制允许在哪个点进行子类化。与简单的多态覆盖相反,其中基本方法将被完全重写,允许彻底改变工作流,只允许更改工作流的特定细节。

控制结构(控制反转)是应用模板模式的结果,通常被称为好莱坞原则:“不要打电话给我们,我们会打电话给你”。使用此原则,父类中的模板方法通过根据需要调用子类方法来控制整个过程。

简单来说,您在基类中定义了框架,派生类实现了实现之间的差异。

假设我们有信息,必须发布到不同的渠道 所以我们制作基类Publisher,它有骨架怎么做。
我们强制实现初始化,每个派生都会设置地址发布的地址 我们制作适合大多数频道的发送实现,如果某个频道使用ftp而不是http,我们会覆盖发送 记录到dababase所做的事情对所有频道来说都是一样的,所以我们不要试图覆盖它 只有发布才属于Publisher derrived类的用户,因此只有该方法是公开的。

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)
     }
}

答案 1 :(得分:1)

这个想法是你有一个方法的多个公共重载,它们都在内部使用单个方法。因此,没有任何公共超载具有实现本身。相反,受保护的方法用于实际实现所有重载。

首先,你不要重复自己,因为你只有一次实现,所有带默认值的重载只是通过设置一些默认值来调用实现。

现在继承该类时,派生类可以简单地覆盖内部实现一次,所有以前的公共重载将立即使用新实现。因此,您可以使用标准实现在基类中指定公共接口,但允许派生类在遵守接口契约时更改该实现。

现在有人可能会争论为什么将实施放在一个单独的方法中,我真的不知道。相反,人们可以轻松地实现方法的最通用签名,并简单地使其他方法调用该方法而不是内部方法。单独方法的原因可能是您可以添加公共方法不可见的内部使用参数,但我想这取决于您想要做什么。

答案 2 :(得分:0)

您可以搜索模板方法设计模式。此模式包含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()");

    }

  }

}

参考:Template Method Design Pattern