Computer Science 209 The Singleton Pattern
Random Numbers System.out.println((int)(Math.random() * 6) + 1); Math.random() uses a single generator that is seeded at the startup of the JVM. The seed is calculated as a function of the computer’s clock Kind of a pain to use to obtain random integers
java.util.Random The Random class is much more convenient to use java.util.Random generator = new java.util.Random(); System.out.println(generator.nextInt(6) + 1); System.out.println(generator.nextDouble()); System.out.println(generator.nextBoolean()); The Random class is much more convenient to use A Random object is also seeded from the clock
java.util.Random java.util.Random generator1 = new java.util.Random(); java.util.Random generator2 = new java.util.Random(); System.out.println(generator1.nextInt(6) + 1); System.out.println(generator2.nextInt(6) + 1); If distinct Random objects are seeded during the same millisecond, they will get the same seed and generate the same pseudo-random sequence
Rolling a Die import java.util.Random; public class Die{ private int value; private Random generator; public Die(){ value = 0; generator = new Random(); } public void roll(){ value = generator.nextInt(6) + 1; public String toString(){ return "" + value;
Rolling a Die private Die die1 = new Die(); public DiceApp(){ setTitle("Roll the Dice"); diceField1.setEditable(false); diceField2.setEditable(false); rollButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ die1.roll(); die2.roll(); diceField1.setText(die1.toString()); diceField2.setText(die2.toString()); } }); Container c = getContentPane(); JPanel panel = new JPanel(); panel.add(diceField1); panel.add(diceField2); c.add("Center", panel); c.add("South", rollButton);
Two Won’t Work The two dice are created within a millisecond of each other, so their random number generators produce the same sequence of numbers We need a way of sharing one instance of Random among all dice
The Context of the Singleton Pattern All clients need to share a single instance of a class No additional instances can be created accidentally
Solution of the Singleton Pattern Define a class with a private constructor The class constructs a single instance of itself The class includes a static method to return the single instance
A Better Random import java.util.Random; public class SingleRandom{ private static SingleRandom instance = new SingleRandom(); private Random generator; private SingleRandom(){ generator = new Random(); } public int nextInt(int limit){ return generator.nextInt(limit); public static SingleRandom getInstance(){ return instance;
A Better Die public class BetterDie{ private int value; private SingleRandom generator; public BetterDie(){ value = 0; generator = SingleRandom.getInstance(); } public void roll(){ value = generator.nextInt(6) + 1; public String toString(){ return "" + value;
Playing Cards Suits are strings, but should not be just any strings import javax.swing.*; public class Card implementsComparable<Card>{ private String suit; private int rank; public Card(String suit, int rank){ this.suit = suit; this.rank = rank; } Suits are strings, but should not be just any strings Must check and throw exceptions to enforce proper use Card queenOfSpades = new Card("spades", 12); Card twoOfHearts = new Card("hearts", 2);
Define a New Type for Suits import javax.swing.*; public class Card implementsComparable<Card>{ private Suit suit; private int rank; public Card(Suit suit, int rank){ this.suit = suit; this.rank = rank; } The type Suit is restricted to just 4 values The compiler enforces their proper use Card queenOfSpades = new Card(Suit.spade, 12); Card twoOfHearts = new Card(Suit.heart, 2);
Similar to the singleton, but has 4 instances public class Suit implements Comparable<Suit>{ static public final Suit spade = new Suit(4, "spades"); static public final Suit heart = new Suit(3, "hearts"); static public final Suit diamond = new Suit(2, "diamonds"); static public final Suit club = new Suit(1, "clubs"); private int order; private String name; private Suit(int ord, String nm){ name = nm; order = ord; } public int compareTo(Suit other){ return order - other.order; public String toString(){ return name; Similar to the singleton, but has 4 instances
Problem with Decks of Cards Every time you create a new deck, the card images must be reloaded from disk If you do this in an applet, they’re reloaded from a remote Web server Decks are mutable, but cards are not
Solution: 52 Singleton Cards The Card class maintains a static list of all cards, which are instantiated just once, when the first card is instantiated When new decks are instantiated, they receive references to cards in this list Card queenOfSpades = Card.newInstance(Suit.spade, 12); Card twoOfHearts = Card.newInstance(Suit.heart, 2);