160 likes | 226 Views
Computer Science 209. The Singleton Pattern. Random Numbers. System.out.println((int)(Math.random() * 6) + 1); System.out.println((int)(Math.random() * 6) + 1);.
E N D
Computer Science 209 The Singleton Pattern
Random Numbers System.out.println((int)(Math.random() * 6) + 1); 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 java.util.Random generator = new java.util.Random(); System.out.println(generator.nextInt(6) + 1); 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(); private Die die2 = 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 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);
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(intord, String nm){ name = nm; order = ord; } public intcompareTo(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);