Lesson 5
Applying Creational Patterns in a Banking System
Applying Creational Patterns in Banking System

You've learned so much about creational patterns, and it's time to apply what you know to a real-world project: a banking system. In this unit, we'll focus on using creational patterns to manage and simplify the creation of banking system components.

Quick Pattern Refresher

Before we dive in, let's quickly recap the creational patterns we'll use:

  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 alter the type of objects that will be created.
  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.

We will implement these patterns to create a logger, accounts, and account factories for 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 of the logger exists throughout the application using Lazy<Logger>.
  2. Accounts using the Factory Method Pattern: Different types of accounts (SavingsAccount and CurrentAccount) created via a factory method.
  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.
Singleton Pattern for Logger

First, let's create a logger using the Singleton Pattern. This will ensure that there is only one instance of the logger throughout the application.

C#
1// Sealed Logger class, preventing inheritance 2public sealed class Logger 3{ 4 // Private constructor to restrict instantiation 5 private Logger() { } 6 7 // Static variable for holding the singleton instance 8 private static readonly Lazy<Logger> instance = new Lazy<Logger>(() => new Logger()); 9 10 // Public static method to retrieve the singleton instance 11 public static Logger Instance => instance.Value; 12 13 // Public method to log a message to the console 14 public void Log(string message) 15 { 16 Console.WriteLine(message); 17 } 18}

Here, the Logger class ensures that only one instance of the logger exists. The Lazy<Logger> type provides thread-safe lazy initialization, and the Instance property is used to access the single instance. Whenever a message needs to be logged, the single instance is used.

Accounts Using Factory Method Pattern

Next, we will create different types of accounts using the Factory Method Pattern. This will allow us to create specific types of accounts while adhering to a common interface.

C#
1public abstract class Account 2{ 3 public abstract void Display(); 4} 5 6public class SavingsAccount : Account 7{ 8 public override void Display() 9 { 10 Logger.Instance.Log("Savings Account created."); 11 } 12} 13 14public class CurrentAccount : Account 15{ 16 public override void Display() 17 { 18 Logger.Instance.Log("Current Account created."); 19 } 20}

In this example, Account is an abstract class with a Display method that needs to be implemented by its subclasses. SavingsAccount and CurrentAccount provide specific implementations of the Display method, logging messages to indicate their creation.

Abstract Factory Pattern for Creating Accounts

Now, let's move on to the Abstract Factory Pattern to create account factories, which will instantiate different types of accounts.

C#
1public abstract class AccountFactory 2{ 3 public abstract Account CreateAccount(); 4} 5 6public class SavingsAccountFactory : AccountFactory 7{ 8 public override Account CreateAccount() 9 { 10 return new SavingsAccount(); 11 } 12} 13 14public class CurrentAccountFactory : AccountFactory 15{ 16 public override Account CreateAccount() 17 { 18 return new CurrentAccount(); 19 } 20}

Here, AccountFactory is an abstract factory that defines the method CreateAccount. SavingsAccountFactory and CurrentAccountFactory are concrete factories that override this method to return instances of SavingsAccount and CurrentAccount, respectively.

Code Integration

To integrate these patterns into a cohesive system, let's see how the different components work together.

C#
1class Program 2{ 3 static void Main() 4 { 5 // Create a savings account using the SavingsAccountFactory 6 AccountFactory savingsFactory = new SavingsAccountFactory(); 7 Account savingsAccount = savingsFactory.CreateAccount(); 8 savingsAccount.Display(); 9 // Output: Savings Account created. 10 11 // Create a current account using the CurrentAccountFactory 12 AccountFactory currentFactory = new CurrentAccountFactory(); 13 Account currentAccount = currentFactory.CreateAccount(); 14 currentAccount.Display(); 15 // Output: Current Account created. 16 } 17}

In this code, we create instances of SavingsAccountFactory and CurrentAccountFactory. We use these factories to create savingsAccount and currentAccount, respectively. Each account's creation is logged using the logger.

Conclusion

Understanding creational patterns in the context of a banking system not only strengthens your coding skills but also demonstrates their utility in real-world applications. These patterns help you maintain code quality by ensuring your code is clean, modular, and easy to understand. They encourage reusability, allowing you to reuse common components across different parts of the system and enhance flexibility by enabling changes and extensions with minimal impact on existing code.

By mastering these patterns, you'll be equipped to build robust and scalable systems efficiently.

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