25% developed

Template method

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Strategy Computer Science Design Patterns
Template method
Visitor

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of algorithm without changing the algorithm's structure.

Implementation in C#
using System;

  class MainApp
  {
    static void Main()
    {
      AbstractClass c;
 
      c = new ConcreteClassA();
      c.TemplateMethod();

      c = new ConcreteClassB();
      c.TemplateMethod();

      // Wait for user
      Console.Read();
    }
  }

  // "AbstractClass"
  abstract class AbstractClass
  {
    public abstract void PrimitiveOperation1();
    public abstract void PrimitiveOperation2();
    // The "Template method"
    public void TemplateMethod()
    {
      PrimitiveOperation1();
      PrimitiveOperation2();
      Console.WriteLine("");
    }
  }

  // "ConcreteClass"
  class ConcreteClassA : AbstractClass
  {
    public override void PrimitiveOperation1()
    {
      Console.WriteLine("ConcreteClassA.PrimitiveOperation1()");
    }
    public override void PrimitiveOperation2()
    {
      Console.WriteLine("ConcreteClassA.PrimitiveOperation2()");
    }
  }

  class ConcreteClassB : AbstractClass
  {
    public override void PrimitiveOperation1()
    {
      Console.WriteLine("ConcreteClassB.PrimitiveOperation1()");
    }
    public override void PrimitiveOperation2()
    {
      Console.WriteLine("ConcreteClassB.PrimitiveOperation2()");
    }
  }
Implementation in Java
/**
 * An abstract class that is common to several games in
 * which players play against the others, but only one is
 * playing at a given time.
 */
abstract class Game {

    protected int playersCount;
    abstract void initializeGame();
    abstract void makePlay(int player);
    abstract boolean endOfGame();
    abstract void printWinner();

    /* A template method : */
    public final void playOneGame(int playersCount) {
        this.playersCount = playersCount;
        initializeGame();
        int j = 0;
        while (!endOfGame()) {
            makePlay(j);
            j = (j + 1) % playersCount;
        }
        printWinner();
    }
}
// Now we can extend this class in order
// to implement actual games:

class Monopoly extends Game {

    /* Implementation of necessary concrete methods */
    void initializeGame() {
        // Initialize players
        // Initialize money
    }

    void makePlay(int player) {
        // Process one turn of player
    }

    boolean endOfGame() {
        // Return true if game is over
        // according to Monopoly rules
    }

    void printWinner() {
        // Display who won
    }

    /* Specific declarations for the Monopoly game. */

    // ...
}
import java.util.Random;

class SnakesAndLadders extends Game {

    /* Implementation of necessary concrete methods */
    void initializeGame() {
        // Initialize players
        playerPositions = new int[playersCount];
        for (int i = 0; i < playersCount; i++) {
           playerPositions[i] = 0;
        }

        die = new Random();

        winnerId = -1;
    }

    void makePlay(int player) {
        // Roll the die
        int dieRoll = die.nextInt(6) + 1;

        // Move the token
        playerPositions[player] += dieRoll;

        // Move up or down because of the ladders or the snakes
        int penaltyOrBonus = board[playerPositions[player]];
        playerPositions[player] += penaltyOrBonus;

        if (playerPositions[player] > 8) {
           // Has reached the top square
           winnerId = player;
        }
    }

    boolean endOfGame() {
        // The game is over when a winner exists
        return (winnerId != -1);
    }

    void printWinner() {
        System.out.println("Player #" + winnerId + " has won!");
    }

    /* Specific declarations for the Snakes and Ladders game. */

    // The board from the bottom square to the top square
    // Each integer is a square
    // Negative values are snake heads with their lengths
    // Positive values are ladder bottoms with their heights
    private static final int[] board = {0, 0, -1, 0, 3, 0, 0, 0, -5, 0};

    // The player positions
    // Each integer represents one player
    // The integer is the position of the player (index) on the board
    private int[] playerPositions = null;

    private Random die = null;

    private int winnerId = -1;
}
Implementation in Java 8 with functional interfaces
/**
 * The same example from above but with Java 8 
 * functional interfaces. Note that now Game
 * class doesn't have to be abstract.
 */
class Game {
    protected int playersCount;

    /*
     * Note that abstract methods are now replaced
     * with functional interface instances. It gives you a lot
     * more of flexibility: you can require all of them to be set
     * via constructor, you can wrap them or you can set default
     * implementations.
     */
    private final Runnable initializeGame;
    private final Consumer<Integer> makePlay;
    private final Supplier<Boolean> endOfGame;
    private final Runnable printWinner;

    /*
     * Constructor with parameters initialization.
     * Note that you can define multiple constructors
     * with different sets of parameters or define
     * default values for null values. Subclasses
     * are required to call at least one of constructors
     * if you don't define a default one.
     */
    protected Game(Consumer<Integer> makePlay, Supplier<Boolean> endOfGame) {
        // you can set default if omitted
        this.makePlay = Optional.ofNullable(makePlay).orElseGet((i)->{});
        // you can require non-null param
        this.endOfGame = Objects.requireNonNull(endOfGame);
        // ... and set defaults for optional parameters
        this.initializeGame = ()->{};
        this.printWinner = ()->{};
    }

    /*
     * Provide setters for customization if you don't provide
     * constructor for every combination of parameters.
     */
     protected void setGameInitializer(Runnable initializeGame) {
        this.initializeGame = Objects.requireNonNull(initializeGame);
     }

     protected void setWinnerPrinter(Runnable printWinner) {
        this.printWinner = Objects.requireNonNull(printWinner);
     }

    /* A template method calling functional interfaces: */
    public final void playOneGame(int playersCount) {
        this.playersCount = playersCount;
        initializeGame.run();
        int j = 0;
        while (!endOfGame.get()) {
            makePlay.accept(j);
            j = (j + 1) % playersCount;
        }
        printWinner.run();
    }
}
// Now we can extend this class in order
// to implement an actual game.
// Note that there's no need to define methods
// that you don't want to override. For methods
// you'd like to override you can either supply
// a functional reference or a lambda:
class Monopoly extends Game {

    public Monopoly() {
        //Initialize parent with functional references
        super(this::makePlay, this::endOfGame);
        // make additional tweaking if you need to.
        // you can even change it in runtime if you want!
        setGameInitializer(this::startGame);
    }

    /*
     * Implementation of concrete method. Note that names
     * can be different now!
     */
    void startGame() {
        // Initialize players
        // Initialize money
    }

    void makePlay(int player) {
        // Process one turn of player
    }

    boolean endOfGame() {
        // Return true if game is over
        // according to Monopoly rules
    }

    /* Specific declarations for the Monopoly game. */

    // ...
}
Implementation in PHP
abstract class Game
{
    abstract protected void initialize();
    abstract protected void startPlay();
    abstract protected void endPlay();

    /** Template method */
    public final void play()
    {
        /** Primitive */
        initialize();

        /** Primitive */
        startPlay();

        /** Primitive */
        endPlay();
    }
}

class Mario extends Game
{
    protected void initialize()
    {
        echo "Mario Game Initialized! Start playing.", PHP_EOL;
    }

    protected void startPlay()
    {
        echo "Mario Game Started. Enjoy the game!", PHP_EOL;
    }

    protected void endPlay()
    {
        echo "Mario Game Finished!", PHP_EOL;
    }
}

class Tankfight extends Game
{
    protected void initialize()
    {
        echo "Tankfight Game Initialized! Start playing.", PHP_EOL;
    }

    protected void startPlay()
    {
        echo "Tankfight Game Started. Enjoy the game!", PHP_EOL;
    }

    protected void endPlay()
    {
        echo "Tankfight Game Finished!", PHP_EOL;
    }
}

$game = new Tankfight();
$game->play();

$game = new Mario();
$game->play();
Implementation in Scala
case class Song(name: String, lyrics: String, music: String)

trait ConcertPlayer {
  def specialEffectsStart()

  def greetTheAudience()

  def introduceYourSelf()

  def songsIterator(): Iterable[Song]

  def sayGoodbye()

  final def playConcert() {
    specialEffectsStart()
    greetTheAudience()
    introduceYourSelf()
    songsIterator() foreach { song =>
      println(s"Now we will play the song named ${song.name}")
      println(song.music)
      println(song.lyrics)
    }
    sayGoodbye()
  }
}

class Artist1 extends ConcertPlayer {
  def sayGoodbye() {
    println("See you!")
  }

  def songsIterator(): Iterable[Song] =
    1 to 10 map { index =>
      Song(s"song $index", s"lyrics $index", s"music $index")
    }

  def introduceYourSelf() {
    println("I'm the Artist1!")
  }

  def greetTheAudience() {
    println("Hey!")
  }

  def specialEffectsStart() {
    println("Pyrotechnics...")
  }
}

class Artist2 extends ConcertPlayer {
  def sayGoodbye() {
    println("Bye-Bye")
  }

  def songsIterator(): Iterable[Song] =
    11 to 21 map { index =>
      Song(s"song $index", s"lyrics $index", s"music $index")
    }

  def introduceYourSelf() {
    println("I'm the Artist2!")
  }

  def greetTheAudience() {
    println("Hi!")
  }

  def specialEffectsStart() {
    println("Flames...")
  }
}

object TemplateMethodTest extends App {
  val artist1 = new Artist1
  val artist2 = new Artist2
  artist1.playConcert()
  artist2.playConcert()
}


Clipboard

To do:
Add more illustrations.


Strategy Computer Science Design Patterns
Template method
Visitor


You have questions about this page?
Ask it here:


Create a new page on this book: