¿Cuál es la diferencia entre el método de plantilla y los patrones de estrategia?


161

¿Puede alguien explicarme cuál es la diferencia entre el patrón de método de plantilla y el patrón de estrategia?

Por lo que puedo decir, son 99% iguales, la única diferencia es que el patrón del método de plantilla tiene una clase abstracta como la clase base, mientras que la clase de estrategia utiliza una interfaz implementada por cada clase de estrategia concreta.

Sin embargo, en lo que respecta al cliente , se consume exactamente de la misma manera: ¿es esto correcto?


2
Esta publicación en SO tiene una mejor respuesta para la misma pregunta: stackoverflow.com/questions/464524/…
Gob00st

12
La pregunta a la que gob00st está vinculada es la diferencia entre estrategia y puente. No es la respuesta a esta pregunta en absoluto.
bluekeys

Respuestas:


135

La principal diferencia entre los dos es cuando se elige el algoritmo concreto.

Con el patrón de método de plantilla, esto sucede en tiempo de compilación al subclasificar la plantilla. Cada subclase proporciona un algoritmo concreto diferente al implementar los métodos abstractos de la plantilla. Cuando un cliente invoca métodos de la interfaz externa de la plantilla, la plantilla llama a sus métodos abstractos (su interfaz interna) según sea necesario para invocar el algoritmo.

class ConcreteAlgorithm : AbstractTemplate
{
    void DoAlgorithm(int datum) {...}
}

class AbstractTemplate
{
    void run(int datum) { DoAlgorithm(datum); }

    virtual void DoAlgorithm() = 0; // abstract
}

Por el contrario, el patrón de estrategia permite elegir un algoritmo en tiempo de ejecución mediante contención . Los algoritmos concretos se implementan mediante clases o funciones separadas que se pasan a la estrategia como un parámetro para su constructor o para un método de establecimiento. El algoritmo elegido para este parámetro puede variar dinámicamente según el estado o las entradas del programa.

class ConcreteAlgorithm : IAlgorithm
{
    void DoAlgorithm(int datum) {...}
}

class Strategy
{
    Strategy(IAlgorithm algo) {...}

    void run(int datum) { this->algo.DoAlgorithm(datum); }
}

En resumen:

  • Patrón de método de plantilla: selección del algoritmo en tiempo de compilación mediante subclases
  • Patrón de estrategia: selección del algoritmo en tiempo de ejecución por contención

47
Ambos patrones admiten la selección en tiempo de ejecución del algoritmo utilizado (para el Método de plantilla, haría algo como if (config.useAlgoA) impl = new AlgoA() else impl = new AlgoB()), por lo que esta respuesta es incorrecta.
Borek Bernard

13
Claro que podrías hacer eso, pero no estás usando el Patrón de plantilla. De hecho, ¡eso es casi exactamente como se verá el código que crea la instancia de Strategy!
thehouse

21
-1, creo que esta respuesta (aunque no está completamente equivocada), pierde el punto donde están las diferencias reales. La respuesta de @Tvanfosson es mucho mejor.
Doc Brown

1
@Karoly Nyisztor Ambos pueden "reemplazar el comportamiento" y "proporcionar puntos de extensión". Si algo es un comportamiento o una extensión, depende realmente del contexto en el que aplique un patrón dado. También puede llamar a cada subclase del patrón de método de plantilla una "estrategia", o llamar a cada clase de estrategia en el patrón de estrategia una "extensión", es solo una redacción. El hecho es que hacen lo mismo, EXCEPTO la diferencia que menciona esta respuesta. Entonces esta es la respuesta correcta.
Andy

1
Se elige un algoritmo concreto de la misma manera para ambos patrones. La elección se realiza invocando new ConcreteAlgorithm1()versus new ConcreteAlgorithm2(). Obviamente, la elección ocurre en tiempo de ejecución (hacer una elección de algoritmo en tiempo de compilación significaría codificarlo). La principal diferencia entre los dos es cómo se implementa el algoritmo concreto. ¿Se implementa como una subclase o como una interfaz separada? El primero es una plantilla. Este último es una estrategia. La diferencia puede resumirse como composición versus herencia, que es un tema común del libro GoF.
jaco0646

138

El patrón de plantilla se usa cuando una operación particular tiene algunos comportamientos invariables que se pueden definir en términos de otros comportamientos primitivos variables. La clase abstracta define los comportamientos invariantes, mientras que las clases implementadoras definen los métodos dependientes.

En una estrategia, las implementaciones de comportamiento son independientes: cada clase de implementación define el comportamiento y no hay código compartido entre ellas. Ambos son patrones de comportamiento y, como tales, los clientes los consumen de la misma manera. Por lo general, las estrategias tienen un único método público: el execute()método, mientras que las plantillas pueden definir un conjunto de métodos públicos, así como un conjunto de primitivas privadas de soporte que las subclases deben implementar.

Los dos patrones podrían usarse fácilmente juntos. Es posible que tenga un patrón de estrategia donde varias implementaciones pertenecen a una familia de estrategias implementadas usando un patrón de plantilla.


Esto me suena bien, sin embargo, ¿por qué WikiPedia menciona que "el patrón de estrategia es que el comportamiento de un algoritmo se seleccione en tiempo de ejecución"? ¿También podría usarse para seleccionar el comportamiento del algoritmo en tiempo de compilación, al igual que el método de plantilla? ¿Me estoy perdiendo de algo?
BornToCode

2
@BornToCode Supongo que de lo que están hablando es de elegir una estrategia particular en tiempo de ejecución. Por ejemplo, hay varias formas de encontrar numéricamente las raíces de una ecuación. Dependiendo del dominio del problema o de los datos, puede elegir Newton-Raphson, Euler o alguna otra estrategia para resolver la ecuación. Cada uno de esos es una estrategia. El algoritmo más grande, del cual resolver la ecuación es una parte, elige la estrategia a emplear en función de alguna calidad del problema.
tvanfosson

Sí, pero no es como si el patrón estratégico se usara SOLO para esos casos. Quiero decir, si solo necesito seleccionar el comportamiento del algoritmo en el momento de la compilación, ¿aún debería usar un patrón de estrategia, o no estaba destinado a usarse de esa manera?
BornToCode

1
@BornToCode Diría que una estrategia es más útil cuando la elección es dinámica. La plantilla es básicamente una forma de construir comportamientos diferentes y relacionados para lo conocido. Usaría alguna estrategia (aunque no necesariamente el patrón de estrategia) para elegir qué comportamiento con plantilla emplear. Por ejemplo, herencia del producto: crearía un producto base, agregaría características para diferentes productos. Elegir qué tipo de producto (clase) instanciar dependerá de qué tablas / vistas se cargue. El patrón de estrategia realmente no entra en juego allí.
tvanfosson

2
@BornToCode no es una cosa o una cosa, es sí y sí. Aplica el patrón donde sea apropiado, combina patrones donde sea útil.
tvanfosson

26

Creo que los Diagramas de clase de ambos patrones muestran las diferencias.

Estrategia
Encapsula un algoritmo dentro de una clase
Enlace a imagen ingrese la descripción de la imagen aquí

Método de plantilla
Aplaza los pasos exactos de un algoritmo a una subclase
Link to Image ingrese la descripción de la imagen aquí


24

Probablemente te refieres al patrón de método de plantilla. Tienes razón, atienden necesidades muy similares. Diría que es mejor usar el método de plantilla en los casos en que tiene un algoritmo de "plantilla" que tiene pasos definidos donde las subclases anulan estos pasos para cambiar algunos detalles. En el caso de la estrategia, debe crear una interfaz y, en lugar de la herencia, está utilizando la delegación. Diría que es un patrón un poco más poderoso y quizás mejor de acuerdo con los principios de inversión de dependencia DIP. Es más poderoso porque define claramente una nueva abstracción de la estrategia, una forma de hacer algo que no se aplica al método de plantilla. Entonces, si esta abstracción tiene sentido, úsela. Sin embargo, el uso del método de plantilla puede proporcionarle diseños más simples en casos simples, lo que también es importante. Considere qué palabras se ajustan mejor: ¿tienes un algoritmo de plantilla? ¿O es la clave aquí que tienes una abstracción de la estrategia: una nueva forma de hacer algo?

Ejemplo de un método de plantilla:

Application.main()
{
Init();
Run();
Done();
}

Aquí hereda de la aplicación y sustituye lo que se hará exactamente en init, run y done.

Ejemplo de una estrategia:

array.sort (IComparer<T> comparer)

Aquí, al escribir un comparador, no se hereda de una matriz. La matriz delega el algoritmo de comparación a un comparador.


3
Creo que esta es una gran respuesta
Calanus

23

Diferencia entre la estrategia y el método de plantilla.


Similitudes

Los patrones de estrategia y método de plantilla tienen muchas similitudes entre ellos. Tanto los patrones de método de Estrategia como los de Plantilla se pueden usar para satisfacer el Principio de Cerrado Abierto y hacer que el módulo de software sea fácil de extender sin cambiar su código. Ambos patrones representan la separación de la funcionalidad genérica de la implementación detallada de esa funcionalidad. Sin embargo, difieren un poco en términos de granularidad que ofrecen.


Las diferencias

Estas son algunas de las diferencias que he observado al estudiar estos dos patrones:

  1. En Estrategia, el acoplamiento entre el cliente y la estrategia es más laxo, mientras que en Método de plantilla, los dos módulos están más estrechamente acoplados.
  2. En Estrategia, se usa principalmente una interfaz, aunque la clase abstracta también se puede usar dependiendo de la situación, y la clase concreta no se usa, mientras que en el método de Plantilla se usa principalmente la clase abstracta o la clase concreta, no se usa la interfaz.
  3. En el patrón de estrategia, generalmente el comportamiento completo de la clase se representa en términos de una interfaz, por otro lado, el método de plantilla se usa para reducir la duplicación de código y el código repetitivo se define en el marco base o la clase abstracta. En el Método de plantilla, incluso puede haber una clase concreta con implementación predeterminada.
  4. En palabras simples, puede cambiar toda la estrategia (algoritmo) en el patrón de Estrategia, sin embargo, en el método de Plantilla, solo algunas cosas cambian (partes del algoritmo) y el resto de las cosas permanecen sin cambios. En el Método de plantilla, los pasos invariantes se implementan en una clase base abstracta, mientras que a los pasos variantes se les da una implementación predeterminada o ninguna implementación. En el método de plantilla, el diseñador de componentes ordena los pasos necesarios de un algoritmo y el orden de los pasos, pero permite que el cliente del componente extienda o reemplace algunos de estos pasos.

La imagen está tomada del blog mordido .



11

Ambos son muy similares y el código del cliente los consume de manera similar. A diferencia de lo que dice la respuesta más popular anterior, ambas permiten la selección de algoritmos en tiempo de ejecución .

La diferencia entre los dos es que, si bien el patrón de estrategia permite que diferentes implementaciones utilicen formas completamente diferentes de lograr el resultado deseado, el patrón del método de plantilla especifica un algoritmo general (el método de "plantilla") que se utiliza para lograr el resultado: - la única opción que queda para las implementaciones específicas (subclases) son ciertos detalles de dicho método de plantilla. Esto se hace haciendo que el método de plantilla haga llamadas a uno o más resúmenes métodos que las subclases anulan (es decir, implementan), a diferencia del método de plantilla que no es abstracto y que las subclases no anulan .

El código del cliente realiza una llamada al método de plantilla utilizando una referencia / puntero del tipo de clase abstracta que apunta a una instancia de una de las subclases concretas que se puede determinar en tiempo de ejecución al igual que al usar el Patrón de estrategia.


9

Método de plantilla:

  1. Se basa en la herencia
  2. Define el esqueleto del algoritmo que las subclases no pueden cambiar. Solo ciertas operaciones pueden anularse en subclases
  3. La clase padre controla completamente el algoritmo y difiere solo de ciertos pasos a clases concretas
  4. El enlace se realiza en tiempo de compilación

Estructura de plantilla_método :

ingrese la descripción de la imagen aquí

Estrategia:

  1. Se basa en la delegación / composición
  2. Cambia las tripas del objeto. modificando el comportamiento del método.
  3. Se usa para cambiar entre la familia de algoritmos
  4. Cambia el comportamiento del objeto en tiempo de ejecución al reemplazar completamente un algoritmo con otro algoritmo en tiempo de ejecución
  5. El enlace se realiza en tiempo de ejecución

Estructura de estrategia :

ingrese la descripción de la imagen aquí

Eche un vistazo a los métodos de plantilla y artículos de estrategia para una mejor comprensión.

Artículos Relacionados:

El patrón de diseño de plantilla en JDK no pudo encontrar un método que definiera un conjunto de métodos para ejecutar en orden

Ejemplo del mundo real del patrón de estrategia


3

No, no se consumen necesariamente de la misma manera. El patrón de "método de plantilla" es una forma de proporcionar "orientación" a futuros implementadores. Les está diciendo, "Todos los objetos Persona deben tener un Número de Seguro Social" (ese es un ejemplo trivial pero transmite la idea correctamente).

El patrón de estrategia permite que múltiples implementaciones posibles se puedan activar y desactivar. No se implementa (generalmente) a través de la herencia, sino que deja que la persona que llama pase la implementación deseada. Un ejemplo podría ser permitir que se proporcione a ShippingCalculator una de varias formas diferentes de calcular los impuestos (una implementación NoSalesTax y una implementación PercentageBasedSalesTax, tal vez).

Entonces, a veces, el cliente le dirá al objeto qué estrategia usar. Como en

myShippingCalculator.CalculateTaxes(myCaliforniaSalesTaxImpl);

Pero el cliente nunca haría eso por un objeto basado en el Método de plantilla. De hecho, es posible que el cliente ni siquiera sepa que un objeto se basa en el Método de plantilla. Esos métodos abstractos en el patrón Método de plantilla podrían incluso estar protegidos, en cuyo caso el cliente ni siquiera sabría que existen.


3

Te sugiero que leas este artículo. Explica las diferencias en un ejemplo de caso real.

Cita del articulo

" Como se puede ver, las clases de implementación también dependen de la clase de método de la plantilla. Esta dependencia hace que cambie el método de la plantilla si uno quiere cambiar algunos de los pasos del algoritmo. Por otro lado, la estrategia encapsula completamente el algoritmo. Le da a la implementación clases para definir completamente un algoritmo. Por lo tanto, si llega algún cambio, uno necesita cambiar el código para las clases previamente escritas. Esta fue la razón principal por la que elegí la estrategia para diseñar las clases.

Una característica del método de plantilla es que el método de plantilla controla el algoritmo. Lo que puede ser algo bueno en otra situación, pero en mi problema esto me estaba restringiendo para diseñar las clases. Por otro lado, la estrategia no controla los pasos de un algoritmo que me permite agregar métodos de conversión completamente diferentes. Por lo tanto, en mi caso, la estrategia me ayuda para la implementación.

Un inconveniente de la estrategia es que hay demasiada redundancia de código y menos intercambio de código. Como es obvio en el ejemplo presentado de este artículo, tengo que repetir el mismo código en cuatro clases una y otra vez. Por lo tanto, es difícil de mantener porque si la implementación de nuestro sistema, como el paso 4, que es común a todos, cambia, entonces tendré que actualizar esto en las 5 clases. Por otro lado, en el método de plantilla, solo puedo cambiar la superclase y los cambios se reflejan en las subclases. Por lo tanto, el método de plantilla proporciona una cantidad muy baja de redundancia y una gran cantidad de código compartido entre las clases.

La estrategia también permite cambiar el algoritmo en tiempo de ejecución. En el método de plantilla, habrá que reinicializar el objeto. Esta característica de la estrategia proporciona una gran cantidad de flexibilidad. Desde el punto de vista del diseño, uno tiene que preferir la composición sobre la herencia. Por lo tanto, usar el patrón de estrategia también se convirtió en la opción principal para el desarrollo "


2

El patrón de plantilla es similar al patrón de estrategia. Estos dos patrones difieren en alcance y metodología.

La estrategia se usa para permitir que las personas que llaman varíen un algoritmo completo, como cómo calcular diferentes tipos de impuestos, mientras que el Método de plantilla se usa para variar los pasos en un algoritmo. Debido a esto, la estrategia es más gruesa. La plantilla permite controles más precisos en la secuencia de operaciones y, sin embargo, permite que las implementaciones de estos detalles varíen.

La otra diferencia principal es que la Estrategia usa la delegación, mientras que el Método de la Plantilla usa la herencia. En Estrategia, el algoritmo se delega a la otra clase xxxStrategy a la que el sujeto tendrá una referencia, pero con Plantilla subclasifica la base y anula los métodos para realizar cambios.

de http://cyruscrypt.blogspot.com/2005/07/template-vs-strategy-patterns.html


2

En el patrón de estrategia, las subclases ejecutan el programa y controlan el algoritmo. Aquí el código se duplica en las subclases. El conocimiento del algoritmo y cómo implementarlo se distribuye en muchas clases.

En el patrón de plantilla, la clase base tiene algoritmo. Maximiza la reutilización entre las subclases. Dado que el algoritmo se encuentra en un lugar, la clase base lo protege.


2

Patrón de diseño de estrategia

  • Apoya la composición.
  • Le brinda la flexibilidad de cambiar el comportamiento del objeto en tiempo de ejecución.
  • Menos acoplamiento entre el código del cliente y el código de solución / algoritmo.

Plantilla Método Diseño Patrón

  • Favorece la herencia sobre la composición
  • Defina algoritmo en su clase base. Las piezas individuales del algoritmo se pueden personalizar en clases secundarias.

1

Patrón de plantilla:

El método de plantilla consiste en permitir que las subclases redefinan ciertos pasos del algoritmo, sin cambiar la estructura principal y los pasos del algoritmo, definidos en la clase base. El patrón de plantilla generalmente usa la herencia, por lo que se puede proporcionar una implementación genérica de algoritmos en la clase base, que la subclase podría optar por anular si es necesario.

public abstract class RobotTemplate {
    /* This method can be overridden by a subclass if required */
    public void start() {
        System.out.println("Starting....");
    }

    /* This method can be overridden by a subclass if required */
    public void getParts() {
        System.out.println("Getting parts....");
    }

    /* This method can be overridden by a subclass if required */
    public void assemble() {
        System.out.println("Assembling....");
    }

    /* This method can be overridden by a subclass if required */
    public void test() {
        System.out.println("Testing....");
    }

    /* This method can be overridden by a subclass if required */
    public void stop() {
        System.out.println("Stopping....");
    }

    /*
     * Template algorithm method made up of multiple steps, whose structure and
     * order of steps will not be changed by subclasses.
     */
    public final void go() {
        start();
        getParts();
        assemble();
        test();
        stop();
    }
}


/* Concrete subclass overrides template step methods as required for its use */
public class CookieRobot extends RobotTemplate {
    private String name;

    public CookieRobot(String n) {
        name = n;
    }

    @Override
    public void getParts() {
        System.out.println("Getting a flour and sugar....");
    }

    @Override
    public void assemble() {
        System.out.println("Baking a cookie....");
    }

    @Override
    public void test() {
        System.out.println("Crunching a cookie....");
    }

    public String getName() {
        return name;
    }
}

Tenga en cuenta que en el código anterior, los pasos del algoritmo go () siempre serán los mismos, pero las subclases pueden definir una receta diferente para realizar un paso en particular.

Patrón de estrategia:

El patrón de estrategia consiste en permitir que el cliente seleccione la implementación de algoritmos concretos en tiempo de ejecución. Todos los algoritmos son aislados e independientes, pero implementan una interfaz común y no existe la noción de definir pasos particulares dentro del algoritmo.

/**
 * This Strategy interface is implemented by all concrete objects representing an
 * algorithm(strategy), which lets us define a family of algorithms.
 */
public interface Logging {
    void write(String message);
}

/**
 * Concrete strategy class representing a particular algorithm.
 */
public class ConsoleLogging implements Logging {

    @Override
    public void write(String message) {
        System.out.println(message); 
    }

}

/**
 * Concrete strategy class representing a particular algorithm.
 */
public class FileLogging implements Logging {

    private final File toWrite;

    public FileLogging(final File toWrite) {
        this.toWrite = toWrite;
    }

    @Override
    public void write(String message) {
        try {
            final FileWriter fos = new FileWriter(toWrite);
            fos.write(message);
            fos.close();
        } catch (IOException e) {
            System.out.println(e);
        }
    }

}

Para obtener el código fuente completo, consulte mi repositorio github .


0

La estrategia se expone como un método de interfaz y plantilla como la clase abstracta. Esto generalmente se usa mucho en frameworks. Por ejemplo, la clase MessageSource de Spring Framework es una interfaz de estrategia para resolver mensajes. El cliente utiliza una implementación particular (estrategia) de esta interfaz.

Y la implementación abstracta de la misma interfaz AbstractMessageSource, que tiene una implementación común de resolución de mensajes y expone el método abstracto resolveCode () para que las subclases puedan implementarlos a su manera. AbstractMessageSource es un ejemplo de método de plantilla.

http://docs.spring.io/spring/docs/4.1.7.RELEASE/javadoc-api/org/springframework/context/support/AbstractMessageSource.html


0

En el método de plantilla de este patrón de diseño, las subclases pueden anular uno o más pasos del algoritmo para permitir diferentes comportamientos y garantizar que se siga el algoritmo general (Wiki).

El método de plantilla de nombre de patrón significa lo que es. Digamos que tenemos un método CalculateSomething () y queremos modelar este método. Este método se declarará en la clase base un método no virtual. Digamos que el método se ve así.

CalculateSomething(){
    int i = 0;
    i = Step1(i);
    i++;
    if (i> 10) i = 5;
    i = Step2(i);
    return i;

} La implementación del método Step1 y Step2 puede ser dada por clases derivadas.

En el Patrón de estrategia no hay una implementación proporcionada por la base (esta es la razón por la cual la base es realmente una interfaz en el diagrama de clases)

El ejemplo clásico es la clasificación. Según la cantidad de objetos que se deben ordenar, se crea la clase de algoritmo apropiada (fusión, burbuja, rápida, etc.) y se encapsula todo el algoritmo en cada clase.

¿Ahora podemos implementar la clasificación como un método de plantilla? Ciertamente puede, pero no encontrará mucho / ningún elemento en común para resumir y colocar en la implementación base. Por lo tanto, derrota el propósito del patrón de método de plantilla.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.