Generics: Defining generic classes

What we’ll cover

Non-Generic vs Generic Structure

Abstracting a Generic Structure

Defining generic classes

Defining a non-Generic Structure

public class BlackJackGameEngine {
  private BlackJackGame game;
  private List<BlackJackPlayer> players;
  public BlackJackGameEngine(BlackJackGame game, List<BlackJackPlayer> players) {
    this.game = game;
    this.players = players;
  }

  public void start() {
    game.addPlayers(players);

    while(!game.isOver()) {
      game.evaluateTurns(players);
    }
  }
}

Defining a non-Generic Structure

public class GoFishGameEngine {
  private GoFishGame game;
  private List<GoFishPlayer> players;
  public GoFishGameEngine(GoFishGame game, List<GoFishPlayer> players) {
    this.game = game;
    this.players = players;
  }

  public void start() {
    game.addPlayers(players);

    while(!game.isOver()) {
      game.evaluateTurns(players);
    }
  }
}

Abstracting a Generic Structure

Abstracting Generic Structures
Player Interface

public interface Player {
  void play();
}
public class GoFishPlayer implements Player {
  // definition omitted for brevity
}
public class BlackJackPlayer implements Player {
  // definition omitted for brevity
}

Abstracting Generic structures
Game Interface

public interface Game {
  void evaluateTurn(Player player);
  void addPlayer(Player player);

  Boolean isOver();
}
public class GoFishGame implements Game {
  // definition omitted for brevity
}
public class BlackJackGame implements Game {
  // definition omitted for brevity
}

Noticing Design Flaw

public void demo() {
  Player player = new BlackJackPlayer();
  Game game = new GoFishGame();

  // no exception thrown; should be impossible behavior
  game.addPlayer(player);
}

Parameterizing Game Interface

Parameterizing GoFish and BlackJack


public class GoFishGame implements Game<GoFishPlayer> {
  // definition omitted for brevity
}
public class BlackJackGame implements Game<BlackJackPlayer> {
  // definition omitted for brevity
}

Noticing Design Advantage
Part 1

public void demo() {
  Player player = new BlackJackPlayer();
  Game<GoFishPlayer> game = new GoFishGame();
  game.addPlayer(player); // compile-time exception
}

Noticing Design Advantage
Part 2

public void demo() {
  Player player = new GoFishPlayer();
  Game<BlackJackPlayer> game = new BlackJackGame();
  game.addPlayer(player); // compile-time exception
}

Noticing Design Advantage
Part 3

public void demo() {
    GoFishPlayer player = new GoFishPlayer();
    Game<GoFishPlayer> game = new GoFishGame();
    game.addPlayer(player); // valid
}

Abstracting Generic structures
Game Engine Interface

public interface GameEngineInterface {
  void start();
  Game getGame();
  Iterable<Player> getPlayers();
}

Abstracting Generic Structures
Game Engine Interface

public abstract class GameEngine implements GameEngineInterface {
  private Game game;
  private List<Player> players;
  public GameEngine(Game game, List<Player> players) {
    this.game = game;
    this.players = players;
  }

  public void start() {
    game.addPlayers(players);

    while(!game.isOver()) {
      game.evaluateTurns(players);
    }
  }
}

Abstracting Generic Structures
Parameterizing Game Engine Interface

public interface GameEngineInterface<
        PlayerType extends Player,
        GameType extends Game<PlayerType>> {

    void start();
    GameType getGame();
    Iterable<PlayerType> getPlayers();
}

Abstracting Generic Structures
Parameterizing Game Engine Class

public abstract class GameEngine<
        PlayerType extends Player,
        GameType extends Game<PlayerType>>
        implements GameEngineInterface<PlayerType, GameType> {

    private GameType game;
    private List<PlayerType> players;
    public GameEngine(GameType game, List<PlayerType> players) {
        this.game = game;
        this.players = players;
    }

    public void start() {
      // definition omitted
    }
}

Abstracting Generic Structures

public class GoFishGameEngine extends GameEngine<GoFishPlayer, GoFishGame> {
  public GoFishGameEngine(GoFishGame game, List<GoFishPlayer> players){
    super(game, players);
  }
}

Former Definition

public class GoFishGameEngine {
  private GoFishGame game;
  private List<GoFishPlayer> players;
  public GoFishGameEngine(GoFishGame game, List<GoFishPlayer> players) {
    this.game = game;
    this.players = players;
  }

  public void start() {
    game.addPlayers(players);

    while(!game.isOver()) {
      game.evaluateTurns(players);
    }
  }
}

Abstracting Generic Structures

public class BlackJackGameEngine extends GameEngine<BlackJackPlayer, BlackJackGame> {
  public BlackJackGameEngine(BlackJackGame game, List<BlackJackPlayer> players){
    super(game, players);
  }
}

Former Definition

public class BlackJackGameEngine {
  private BlackJackGame game;
  private List<BlackJackPlayer> players;
  public BlackJackGameEngine(BlackJackGame game, List<BlackJackPlayer> players) {
    this.game = game;
    this.players = players;
  }

  public void start() {
    game.addPlayers(players);

    while(!game.isOver()) {
      game.evaluateTurns(players);
    }
  }
}