模板方法
外观
定义一个算法的骨架,将一些步骤延迟到子类中。模板方法允许子类在不改变算法结构的情况下,重新定义算法的某些步骤。
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()");
}
}
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;
}
Java 8 使用函数接口的实现
/**
* 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. */
// ...
}
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();
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()
}