CodeBlanks Logo Icon CodeBlanks

Summary - Design patterns

C# course · Advanced · Lesson 66/83

Combine Singleton, Factory and Strategy to write a payment system.

Recap: five patterns

This group covered five patterns: Singleton for one instance; Factory for creation; Strategy for algorithm choice; Observer for change notification; Decorator for wrapping extension. Each solves a different problem; the choice depends on the problem.

Now we combine two of them across two tasks: first Singleton + Factory, then Singleton + Observer. The goal is to see how patterns work together.

Exercise ConfigStore: Singleton + Factory

Define sealed class ConfigStore with a private constructor, a static readonly _instance field, a public static ConfigStore Instance property, and a public string Create(string type) factory method. Create returns "https://example.com" for "url", "Uygulama" for "title", and an empty string otherwise. In Main, print ConfigStore.Instance.Create("title").

Show example solution
//example.com", "title" => "Uygulama", _ => "" }; In Main: Console.WriteLine(ConfigStore.Instance.Create("title"));
Example solution:
using System;

sealed class ConfigStore
{
    private static readonly ConfigStore _instance = new ConfigStore();
    public static ConfigStore Instance => _instance;
    private ConfigStore() { }

    public string Create(string type) =>
        type switch
        {
            "url" => "https://example.com",
            "title" => "Uygulama",
            _ => ""
        };
}

class Program
{
    static void Main()
    {
        Console.WriteLine(ConfigStore.Instance.Create("title"));
    }
}

Exercise Logger: Singleton + Observer

Define sealed class Logger with a private constructor, static readonly _instance, public static Logger Instance, and public event EventHandler<string> MessageLogged. A Log(string message) method calls MessageLogged?.Invoke(this, message). class LoggerMonitor's constructor subscribes to Logger.Instance.MessageLogged with a lambda that writes "Kayıt: " + msg. In Main, create new LoggerMonitor() and call Logger.Instance.Log("Sistem açıldı").

Show example solution
Define sealed class Logger { private static readonly Logger _instance = new Logger(); public static Logger Instance => _instance; private Logger() { } public event EventHandler<string> MessageLogged; public void Log(string message) => MessageLogged?.Invoke(this, message); }. Write class LoggerMonitor { public LoggerMonitor() => Logger.Instance.MessageLogged += (s, msg) => Console.WriteLine("Kayıt: " + msg); }. In Main: var m = new LoggerMonitor(); Logger.Instance.Log("Sistem açıldı");
Example solution:
using System;

sealed class Logger
{
    private static readonly Logger _instance = new Logger();
    public static Logger Instance => _instance;
    private Logger() { }

    public event EventHandler<string> MessageLogged;
    public void Log(string message) => MessageLogged?.Invoke(this, message);
}

class LoggerMonitor
{
    public LoggerMonitor() =>
        Logger.Instance.MessageLogged += (s, msg) =>
            Console.WriteLine("Kayıt: " + msg);
}

class Program
{
    static void Main()
    {
        var monitor = new LoggerMonitor();
        Logger.Instance.Log("Sistem açıldı");
    }
}

Test yourself

  1. Match patterns to their use

    Singleton
    Single-instance guarantee
    Factory
    Object creation
    Strategy
    Algorithm choice
    Observer
    Change notification
    Decorator
    Wrapping extension
  2. Which pattern guarantees a single instance?

    • Observer
    • Singleton
    • Decorator
    • Strategy
    Show answer

    Singleton — Correct. Singleton guarantees one instance.

All lessons in Advanced