2012-07-04 8 views
5

Bueno, estaba repasando this excelente artículo en MSDN sobre "Base Class Usage". Si bien entiendo el concepto de clase base e interfaces, no puedo comprender el uso de los métodos de plantilla en el segundo párrafo de este artículo ("Protected Methods and Constructors").¿Cuál es el uso del Método de plantilla en las clases base?

¿Alguien podría ayudarme a entender este concepto con la ayuda de un simple ejemplo práctico? Tal vez, comprender el concepto de Método de plantilla es un buen lugar para comenzar.

Gracias de antemano.

Respuesta

2

Eso es muy antiguo artículo en mi opinión, no recuerdo haber visto nombrando con Impl.

creo que Wikipedia tiene una mejor descripción:
El método de la plantilla se utiliza para:

  • vamos subclases implementan (a través de primordial método) el comportamiento que puede variar

  • duplicación evitar en el código: la estructura de flujo de trabajo general se implementa una vez en el algoritmo de la clase abstracta, y las variaciones necesarias se implementan en cada una de las subclases.

  • control en qué punto (s) se permite la subclasificación. A diferencia de una anulación polimórfica simple, donde el método base se reescribiría por completo, permitiendo un cambio radical en el flujo de trabajo, solo se permite el cambio de los detalles específicos del flujo de trabajo.

La estructura de control (inversión de control) que es el resultado de la aplicación de un patrón de plantilla se refiere a menudo como el Principio de Hollywood: "No nos llame, le llamaremos". Al usar este principio, el método de la plantilla en una clase principal controla el proceso general llamando a los métodos de las subclases según sea necesario.

En palabras simples, usted define el esqueleto en su clase base, y las clases derivadas implementan las diferencias entre las implementaciones.

Digamos que tenemos información que debe publicarse en diferentes canales.
Así que hacemos Publisher de la clase base, que tiene esqueleto de cómo hacerlo.
Obligamos a implementar la inicialización, que cada derivación establecería la dirección donde publicar.
Realizamos la implementación de envío, que se adapta a la mayoría de los canales y si algún canal usa ftp en lugar de http, permitimos anular el envío.
Y al iniciar sesión en la base de datos, lo que se hizo es lo mismo para todos los canales, por lo que no podemos omitirlo.
Solo la publicación es interesante para el usuario de la clase Derivada por editor, por lo que solo ese método es público.

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

Gracias Giedrius, ese es un ejemplo muy informativo. Creo que realmente entiendo algo de este concepto ahora. Pero no sé si vale la pena profundizar más o si alguien está usando este estilo en el mundo práctico. – Aakash

+0

Estilo de nomenclatura: no, pero el patrón se usa, es útil y bastante natural (natural, es decir, lo estaba usando sin saber que es un patrón bien conocido :). – Giedrius

+0

:-) Quizás no me di cuenta de eso. Aunque es simple y ordenado. Gracias por toda tu ayuda. – Aakash

1

La idea es que tenga múltiples sobrecargas públicas de un método que todos usan internamente un único método. Entonces, ninguna de las sobrecargas públicas tiene la implementación en sí misma. En cambio, se usa un método protegido para la implementación real de todas las sobrecargas.

En primer lugar, no se repita, ya que solo tiene la implementación una vez y todas las sobrecargas con valores predeterminados simplemente llaman a la implementación estableciendo algunos valores predeterminados.

Ahora, al heredar la clase, la clase derivada simplemente puede anular la implementación interna una vez y todas las sobrecargas públicas anteriores utilizarán inmediatamente la nueva implementación. De modo que puede especificar la interfaz pública en la clase base con una implementación estándar, pero permite derivar clases para cambiar esa implementación mientras se cumple el contrato de interfaz.

Ahora uno podría argumentar por qué la implementación se pone en un método separado, y realmente no lo sé. En su lugar, uno podría implementar fácilmente la firma más genérica de un método y simplemente hacer que los otros métodos lo llamen uno en lugar de uno interno. Una razón para un método separado podría ser que podría agregar parámetros de uso interno que no son visibles para los métodos públicos, pero supongo que eso depende de lo que quiera hacer.

+0

¡Gracias !, en este caso particular, es la información que oculta el factor de impulso para separar la implementación del método público. (Además de mantener la estructura/flujo de trabajo igual.) Si lo entendí correctamente, entonces creo que es una construcción de programación muy agradable. ahora me pregunto cuáles podrían ser las desventajas de usar este patrón. – Aakash

0

Puede buscar Patrón de diseño de método de plantilla. Este patrón incluye un método de plantilla, que proporciona una secuencia esquemática de métodos de llamada. Uno o más pasos pueden diferirse a subclases que implementan estos pasos sin cambiar la secuencia general de llamadas. Ejemplo:

// 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: Template Method Design Pattern

Cuestiones relacionadas