Loading...
For each class, define the attributes (data) it will hold and the methods (functions) that operate on the attributes. Ensure they align with the object's responsibilities and adhere to the principle of encapsulation.
class BookStatus(Enum):
AVAILABLE = 1
UNAVAILABLE = 2
class Singleton:
_instance = None
def __new__(cls):
if cls._instanceis None:
cls._instance= super().__new__(cls)
return cls._instance
class GenerateUserID(Singleton):
def init(self):
if getattr(self, "_initialized"):
return
self.userID = 0
def generateID(self):
self.userID += 1
return self.userID
class User:
def init(self, firstName, lastName, phoneNumber, userID):
self.userID = userID
self.firstName = firstName
self.lastName = lastName
self.phoneNumber = phoneNumber
class Book:
def init(self, title, author, status, barcode):
self.title = title
self.author = author
self.status = status
self.barcode = barcode
def checkout(self):
self.status = BookStatus.AVAILABLE
def return(self):
self.status = BookStatus.UNAVAILABLE
class FineManagement:
def init(self):
# key:val = userID:fineAmount
self.dueFines= defaultdict(int)
def fineUser(self, userID, fineAmount):
try:
self.dueFines[userID] += fineAmount
return True
except Exception:
return False
def payFine(self, userID, paidAmount):
if userID in self.finesHistory:
self.dueFines[userID] -= paidAmount
if self.dueFines[userID] == 0:
del self.[userID]
return True
else:
return False
class Trie:
def init(self):
self.dictionary = {}
self.books = set()
def insert(self, word, book):
node = self
for char in word:
if char not in node.dictionary:
node.dictionary[char] = Trie()
node = node.dictionary[char]
node.books.add(book)
def search(self, word):
node = self
for char in word:
if char not in node.dicationry:
return set()
node = node.dictionary[char]
return node.books
class Library:
def init(self, books: list[list[]], users: list[list[]]):
# to note, for userIDGenerator if this was a distributed system we'd use a distributive system manager to generate ID and in DB we could auto increment or use UUID
# opting to use UUID instead of GenerateUserID singleton to reduce latency and avoid race conditions of userID
self.userIDGenerator = GenerateUserID()
self.bookSearchSystem = Trie()
self.fineManagementSystem = FineManagement()
self.books = [Book(title,author,barcode) for title,author,barcode in books]
self.users = [User(firstName,lastName,phoneNumber,userIDGenerator.generateID())]
for book in self.books:
self.bookSearchSystem.insert(book.title,book)
self.bookSearchSystem.insert(book.author,book)
self.bookSearchSystem.insert(book.barcode,book)
def findBook(self, targetString):
# possibly set to min length of say 3-4 to reduce load sent back (number of result)
return self.bookSearchSystem.search(targetString)
def checkoutBook(self, book):
if book.status == BookStatus.AVAILABLE:
book.checkout()
return True
return False
def returnBook(self, book):
if book.status == BookStatus.UNAVAILABLE:
book.return()
return True
return False
def fineUser(self, userID, fineAmount):
self.fineManagementSystem.fineUser(userID, fineAmount)
def payFine(self, userID, paidAmount):
return self.fineManagementSystem.payFine(userID, paidAmount)
Explain design tradeoffs you considered. Check and explain whether your design adheres to SOLID principles. Explain how your design can handle changes in scale and whether it would be easy to extend with new functionalities. Identify areas for future improvement...