Welcome to the final lesson of our "Creational Patterns in Scala" course! 🎉 Good job in making it to the end. So far, you've delved into the world of creational design patterns, mastering concepts like Singleton, Factory Method, Abstract Factory, and Builder. Now, it's time to apply these design patterns to a practical project — a simple banking system. Join us as we navigate through these creational patterns to design and build system components that are not only efficient but also maintainable and scalable. Let's dive into the world of Scala and have some fun creating clean, reusable, and elegant code! 😎
Before we dive into building our banking system, let's quickly recap the key creational design patterns that we encountered in this course:
- Singleton Pattern: Ensures a class has only one instance and provides a global point of access to it.
- Factory Method Pattern: Defines an interface for creating an object, but allows subclasses to specify the type of object they wish to instantiate.
- Abstract Factory Pattern: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
- Builder Pattern: Separates the construction of a complex object from its representation, allowing the same construction process to create various representations.
In this lesson, we'll implement these patterns to create a logger
, accounts
, and account factories
within our banking system.
Let's see what you'll build in this unit. You will create:
- Logger with the Singleton Pattern: A logging mechanism that ensures only one instance exists throughout the application using Scala's
object
. - Accounts using the Factory Method Pattern: Different types of accounts (
SavingsAccount
andCurrentAccount
) created via factory methods. - Account Factories using the Abstract Factory Pattern: Factories that will instantiate different types of accounts.
- Code Integration: Comprehensive integration of these patterns into a cohesive system.
Ready? Let's dive in!
Let's begin by creating a logger using the Singleton Pattern. This ensures that there's only one instance of the logger available throughout the application.
Scala1// Singleton Pattern for Logger in Bank System 2object Logger: 3 def log(message: String): Unit = 4 println(message)
Recall that in Scala, the object
keyword is used to implement the Singleton pattern elegantly. The Logger
object above is a singleton, automatically ensuring that only one instance exists. You can use the log
method to print messages wherever necessary in the application.
Next, we'll create different types of accounts using the Factory Method Pattern. This allows us to generate specific types of accounts while following a common interface.
Scala1// Account hierarchy 2trait Account: 3 def display(): Unit 4 5class SavingsAccount extends Account: 6 def display(): Unit = 7 Logger.log("Savings Account created.") 8 9class CurrentAccount extends Account: 10 def display(): Unit = 11 Logger.log("Current Account created.")
Here, Account
is a trait that defines the display
abstract method. SavingsAccount
and CurrentAccount
are classes implementing this trait, each providing its own implementation of the display
method that logs a message upon their creation.
Now let's implement the Abstract Factory Pattern to define account factories that will create different types of accounts.
Scala1// Abstract Factory Pattern for creating accounts 2trait AccountFactory: 3 def createAccount(): Account 4 5class SavingsAccountFactory extends AccountFactory: 6 def createAccount(): Account = SavingsAccount() 7 8class CurrentAccountFactory extends AccountFactory: 9 def createAccount(): Account = CurrentAccount()
In this code snippet, AccountFactory
is defined as a trait and provides the abstract method createAccount
. Both SavingsAccountFactory
and CurrentAccountFactory
implement this trait, providing specific implementations of createAccount
to instantiate SavingsAccount
and CurrentAccount
, respectively.
Let's see how all these patterns integrate into a coherent system.
Scala1@main def main(): Unit = 2 // Create a savings account using the SavingsAccountFactory 3 val savingsFactory = SavingsAccountFactory() 4 val savingsAccount = savingsFactory.createAccount() 5 savingsAccount.display() 6 // Output: Savings Account created. 7 8 // Create a current account using the CurrentAccountFactory 9 val currentFactory = CurrentAccountFactory() 10 val currentAccount = currentFactory.createAccount() 11 currentAccount.display() 12 // Output: Current Account created.
In this code, we create instances of SavingsAccountFactory
and CurrentAccountFactory
. With these factories, we generate savingsAccount
and currentAccount
, respectively. Each account's creation is logged through the Logger
.
Congratulations on applying creational patterns to build a simple yet effective banking system! By mastering the Singleton, Factory Method, and Abstract Factory patterns, you've extended your coding capabilities into real-world applications. These patterns keep your code clean, modular, and open for further enhancements, ensuring both flexibility and scalability. They encourage reusability, allowing you to reuse common components across different parts of the system. Remember, practice makes perfect 🏋. Continue exploring these patterns across different scenarios to solidify and expand your understanding. Well done, and happy coding in Scala! 🥳