In: Computer Science
In Python 3:
Software Design Patterns may be thought of as blue prints or recipes for implementing common models in software. Much like re-using proven classes in Object Oriented design, re-using proven patterns tends to produce more secure and reliable results often in reduced time compared to re-inventing the wheel. In fact, some high-level languages have integrated facilities to support many common patterns with only minimal, if any, user written software. That said, in software design and construction, often the challenge is to know that a pattern exists and be able to recognize when it is a good fit for a project. To give you a familiar frame of reference, below is a Singleton Pattern implemented in Java:
public class MySingleton {
// reference to class instance
private static MySingleton instance = null;
// Private Constructor
private MySingleton() {
instance = this;
}
// Returns single instance to class
public static MySingleton getInstance() {
if (instance == null) {
instance = new MySingleton();
}
return instance;
}
public static void main(String[] args)
{
MySingleton s1 = MySingleton.getInstance();
MySingleton s2 = MySingleton.getInstance();
System.out.println("s1: " + s1 + " s2: " + s2);
}
}
If you run this example, you will see that the address for s1 and s2 are exactly the same. That is because the pattern restricts the existence of more than one instance in a process. Of course this example only implements the pattern but other functionality can be added to this class just as any other class. The primary features of a singleton are:
The primary goal of this assignment is not to teach you how to write singleton patterns in Python, (though that’s part of it), but to familiarize you with the concept of design patterns as well as give you experience in adapting one into one of your own designs.
Description
Pick one of your previous assignments, either from MindTap or one of your Distributed Systems assignments and integrate a Singleton Pattern into it. Hint: Any class can be made into a Singleton.
Code to integrate Singleton pattern into:
import random
class Card(object):
""" A card object with a suit and rank."""
RANKS = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)
SUITS = ('Spades', 'Diamonds', 'Hearts', 'Clubs')
def __init__(self, rank, suit):
"""Creates a card with the given rank and suit."""
self.rank = rank
self.suit = suit
self.faceup = False
def turn(self):
self.faceup = not self.faceup
def __str__(self):
"""Returns the string representation of a card."""
if self.rank == 1:
rank = 'Ace'
elif self.rank == 11:
rank = 'Jack'
elif self.rank == 12:
rank = 'Queen'
elif self.rank == 13:
rank = 'King'
else:
rank = self.rank
return str(rank) + ' of ' + self.suit
class Deck(object):
""" A deck containing 52 cards."""
def __init__(self):
"""Creates a full deck of cards."""
self.cards = []
for suit in Card.SUITS:
for rank in Card.RANKS:
c = Card(rank, suit)
self.cards.append(c)
def shuffle(self):
"""Shuffles the cards."""
random.shuffle(self.cards)
def deal(self):
"""Removes and returns the top card or None
if the deck is empty."""
if len(self) == 0:
return None
else:
return self.cards.pop(0)
def __len__(self):
"""Returns the number of cards left in the deck."""
return len(self.cards)
def __str__(self):
"""Returns the string representation of a deck."""
result = ''
for c in self.cards:
result = self.result + str(c) + '\n'
return result
def main():
"""A simple test."""
deck = Deck()
print("A new deck:")
while len(deck) > 0:
print(deck.deal())
deck = Deck()
deck.shuffle()
print("A deck shuffled once:")
while len(deck) > 0:
print(deck.deal())
if __name__ == "__main__":
main()
Here is the completed code for this problem. Comments are included, go through it, learn how things work and let me know if you have any doubts or if you need anything to change. If you are satisfied with the solution, please rate the answer. If not, PLEASE let me know before you rate, I’ll help you fix whatever issues. Thanks
Note: Please maintain proper code spacing (indentation), just copy the code part and paste it in your compiler/IDE directly, no modifications required.
Edit: For some reason, I'm unable to reply to your comment due to some technical issues. So I'll reply here. Yes the shuffled deck is empty andbecause the Deck is singleton and all cards have been previously dealt/removed. Follow the comments included in the code for more info.
#code
import random
# Card class, unchanged
# Note: this class cannot be made Singleton, not impossible, but if we do, then
# Deck class would not function correctly (as there could be only one card at a time).
class Card(object):
""" A card object with a suit and rank."""
RANKS = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)
SUITS = ('Spades', 'Diamonds', 'Hearts', 'Clubs')
def __init__(self, rank, suit):
"""Creates a card with the given rank and suit."""
self.rank = rank
self.suit = suit
self.faceup = False
def turn(self):
self.faceup = not self.faceup
def __str__(self):
"""Returns the string representation of a card."""
if self.rank == 1:
rank = 'Ace'
elif self.rank == 11:
rank = 'Jack'
elif self.rank == 12:
rank = 'Queen'
elif self.rank == 13:
rank = 'King'
else:
rank = self.rank
return str(rank) + ' of ' + self.suit
# Deck class made singleton
class Deck(object):
# static variable indicating the instance
__inst = None
# method returning an instance of Deck
@staticmethod
def getInstance():
if Deck.__inst == None: # if __inst is None, calling Deck() constructor once
Deck()
return Deck.__inst # returning the instance
# below method is actually a helper method to destroy singleton instance.
# otherwise, if we deal all cards, we cannot create a new Deck to contain all cards again.
@staticmethod
def destroyInstance():
Deck.__inst = None
def __init__(self):
# if __inst is None, creating a deck and setting this object as __inst
if Deck.__inst == None:
"""Creates a full deck of cards."""
self.cards = []
for suit in Card.SUITS:
for rank in Card.RANKS:
c = Card(rank, suit)
self.cards.append(c)
Deck.__inst = self
else: # otherwise (__inst is not None), raising exception
raise Exception("Singleton class cannot be instantiated multiple times!")
def shuffle(self):
"""Shuffles the cards."""
random.shuffle(self.cards)
def deal(self):
"""Removes and returns the top card or None
if the deck is empty."""
if len(self) == 0:
return None
else:
return self.cards.pop(0)
def __len__(self):
"""Returns the number of cards left in the deck."""
return len(self.cards)
def __str__(self):
"""Returns the string representation of a deck."""
result = ''
for c in self.cards:
result = self.result + str(c) + '\n'
return result
def main():
"""A simple test."""
deck1 = Deck.getInstance()
deck2 = Deck.getInstance() # same object as previous deck
# printing addresses of both decks to let user know that both are same object.
print(repr(deck1))
print(repr(deck2))
print("A new deck:")
while len(deck1) > 0:
print(deck1.deal())
deck2.shuffle()
print("A deck shuffled once:")
# below statements will not print anything because deck is empty. if you want to create
# another deck, first call Deck.destroyInstance() and then call deck2 = Deck.getInstance()
while len(deck2) > 0:
print(deck2.deal())
if __name__ == "__main__":
main()
#output
<__main__.Deck object at 0x00F35C70>
<__main__.Deck object at 0x00F35C70>
A new deck:
Ace of Spades
2 of Spades
3 of Spades
4 of Spades
5 of Spades
6 of Spades
7 of Spades
8 of Spades
9 of Spades
10 of Spades
Jack of Spades
Queen of Spades
King of Spades
Ace of Diamonds
2 of Diamonds
3 of Diamonds
4 of Diamonds
5 of Diamonds
6 of Diamonds
7 of Diamonds
8 of Diamonds
9 of Diamonds
10 of Diamonds
Jack of Diamonds
Queen of Diamonds
King of Diamonds
Ace of Hearts
2 of Hearts
3 of Hearts
4 of Hearts
5 of Hearts
6 of Hearts
7 of Hearts
8 of Hearts
9 of Hearts
10 of Hearts
Jack of Hearts
Queen of Hearts
King of Hearts
Ace of Clubs
2 of Clubs
3 of Clubs
4 of Clubs
5 of Clubs
6 of Clubs
7 of Clubs
8 of Clubs
9 of Clubs
10 of Clubs
Jack of Clubs
Queen of Clubs
King of Clubs
A deck shuffled once: