Port of schuchert.wikispaces.com


Template_Method

Template_Method

Template Method Pattern

This is an example of the GoF design pattern Template Method. Here’s an example taken from Monopoly.

Imagine the game of Monopoly. There are several kinds of (read this as classes of) squares, e.g. Go, Go To Jail, Free Parking, Real Estate. Under Real Estate there are three kinds:

Here’s an algorithm for what happens when the current player lands on a square:

public void landOn(Player p) {
   if(isOwnedBy(p) || isMortgaged()) {
      // player does not pay itself
      // rent not collected if mortgaged
      return;
   }

   if(isOwned()) {
      int rent = calculateRent();
      p.payPlayer(this, rent);
   } else {
      // offer myself for sale to p
   }
}

How do you calculate rent? Here are the three ways you calculate rent:

Type Algorithm
Railroad 25 * number of railroads owned by same player
Utility 4 * current dice roll if only one owned or 10 * current dice roll if both are owned (contrary to popular belief, both do not have to be owned by the same player to get 10X and you do not re-roll the dice either)
Property Some base value modified by houses or hotels on the property

Notice that the rules for landing are the same:

The only step that varies is the calculation of the rent. So we create an abstract base class, called Real Estate, that implements the landOn method AND has one abstract method:

protected int calculateRent();

We then write three derived classes, Railroad, Utility, Property, that each implement calculate rent:

Railroad

class Railroad extends RealEstate {
   protected int calculateRent() {
      Player owner = getOwner();
      PropertyGroup group = getPropertyGroup();
      int numberOwnedBySamePlayer = group.calculateNmberOwnedBy(owner);
      return 25 * numberOwnedBySamePlayer;
   }
}

Utility

class Utility extends RealEstate {
   protected int calculateRent() {
      Dice dice = getDice();
      int currentRollValue = dice.getValue();
      PropertyGroup group = getPropertyGroup();
      int numberOwned = group.getNumberOwned();

      int rentMultiplier = 4;
      if(numberOwned == 2) {
         rentMultiplier = 10;
      }
      return rentMultiplier * currentRollValue;
   }
}

Property

class Property extends RealEstate {
   protected int calculateRent() {
      int baseRent = getBaseRent();
      int houses = getNumberOfHouses();
      // calcualte actual rent value using baseRent and houses
      return calculateActualRent(baseRent, houses);
   }
}

So when a player lands on any kind of RealEstate square, the landOn method in RealEstate performs some basic checks that are true for all kinds of RealEstate types. It then polymorphically the {railroad, utility, property} to calculate the rent, if appropriate, and charges the rent to the current player.


Comments

" Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.