Summary - Design patterns
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
-
Match patterns to their use
- Singleton
- Single-instance guarantee
- Factory
- Object creation
- Strategy
- Algorithm choice
- Observer
- Change notification
- Decorator
- Wrapping extension
-
Which pattern guarantees a single instance?
- Observer
- Singleton
- Decorator
- Strategy
Show answer
Singleton — Correct. Singleton guarantees one instance.