¿Cuál es el uso del método de plantilla en las clases base?

Well, I was going through este excellent article on MSDN about "Base Class Usage". While I understand the concept of base class and interfaces, I am unable to comprehend the usage of Template methods in the second paragraph of this article ("Protected Methods and Constructors").

Could anyone help me to understand this concept with the help of a simple practical example? Perhaps, understanding the concept of Template Method is a good place to start.

Gracias de antemano.

preguntado el 04 de julio de 12 a las 08:07

3 Respuestas

That is very old article in my opinion, don't remember seeing naming with Impl.

I think wikipedia has better description:
El método de la plantilla se utiliza para:

  • permitir que las subclases implementen (a través de la anulación de métodos) un comportamiento que puede variar

  • avoid duplication in the code: the general workflow structure is implemented once in the abstract class's algorithm, and necessary variations are implemented in each of the subclasses.

  • control at what point(s) subclassing is allowed. As opposed to a simple polymorphic override, where the base method would be entirely rewritten allowing radical change to the workflow, only the specific details of the workflow are allowed to change.

The control structure (inversion of control) that is the result of the application of a template pattern is often referred to as the Hollywood Principle: "Don't call us, we'll call you." Using this principle, the template method in a parent class controls the overall process by calling subclass methods as required.

In simple words, you define skeleton in your base class, and derived classes implement differences between implementations.

Let's say we have information, that must be published to different channels.
So we make base class Publisher, that has skeleton how to do that.
We force to implement initialization, that every derive would set address where to publish.
We make sending implementation, that fits most of the channels and if some channel uses ftp instead of http, we let to override sending.
And logging to dababase what was done is the same for all channels, so we don't let to override that.
Only publishing is interesing to user of Publisher derrived class, so only that method is public.

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

Respondido 04 Jul 12, 08:07

Thanks Giedrius, That is a very informative example. I think I really have some grasp of this concept now. But I don't know if it is worth drill it down more or if anyone is using this style in practical world. - Aakash

Naming style - no, but pattern is used, useful and quite natural (natural - I mean I was using it without knowing that is a well known pattern :). - giedrio

:-) Perhaps I didn't noticed that. Though its simple and neat. Thanks for all your help. - Aakash

The idea is that you have multiple public overloads of a method that all internally use a single method. So none of the public overloads has the implementation itself. Instead a protected method is used for the actual implementation of all the overloads.

So first of all, you don’t repeat yourself, as you only have the implementation once and all overloads with defaults simply call the implementation by setting some default values.

Now when inheriting the class, the deriving class can simply override the internal implementation una vez and all previously public overloads will immediately use the new implementation. So you can specify the public interface in the base class with a standard implementation but allow deriving classes to change that implementation while abiding to the interface contract.

Now one could argue why the implementation is put in a separate method, and I seriously don’t know. Instead one could easily implement the most generic signature of a method and simply make the other methods call that one instead of an internal one. A reason for a separate method might be that you could add internal usage parameters that are not visible to the public methods, but I guess that depends on what you want to do.

Respondido 04 Jul 12, 08:07

Thanks!, In this particular case, Is the information hiding the driving factor to separate the implementation from public method. (Apart from keeping the structure/workflow same.) If I understood it correctly, then I think its a very nice programming construct. now I am wondering what could be disadvantages of using this pattern. - Aakash

You can search for Template Method Design Pattern. This pattern includes a Template method, which provides a skeleton calling sequence of methods. One or more steps can be deferred to subclasses which implement these steps without changing the overall calling sequence. Example:

// 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()");

    }

  }

}

Referencia: Patrón de diseño de método de plantilla

Respondido 04 Jul 12, 08:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.