Lesson 5
Applying Creational Patterns in a Scala Banking System
Introduction

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! 😎

Quick Pattern Refresher

Before we dive into building our banking system, let's quickly recap the key creational design patterns that we encountered in this course:

  1. Singleton Pattern: Ensures a class has only one instance and provides a global point of access to it.
  2. Factory Method Pattern: Defines an interface for creating an object, but allows subclasses to specify the type of object they wish to instantiate.
  3. Abstract Factory Pattern: Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
  4. 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.

What You'll Build

Let's see what you'll build in this unit. You will create:

  1. Logger with the Singleton Pattern: A logging mechanism that ensures only one instance exists throughout the application using Scala's object.
  2. Accounts using the Factory Method Pattern: Different types of accounts (SavingsAccount and CurrentAccount) created via factory methods.
  3. Account Factories using the Abstract Factory Pattern: Factories that will instantiate different types of accounts.
  4. Code Integration: Comprehensive integration of these patterns into a cohesive system.

Ready? Let's dive in!

Singleton Pattern for Logger

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.

Scala
1// 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.

Accounts Using Factory Method Pattern

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.

Scala
1// 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.

Abstract Factory Pattern for Creating Accounts

Now let's implement the Abstract Factory Pattern to define account factories that will create different types of accounts.

Scala
1// 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.

Code Integration

Let's see how all these patterns integrate into a coherent system.

Scala
1@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.

Conclusion

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! 🥳

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.