Design Patterns

Reusable solutions to commonly occurring problems in software design (GoF — Gang of Four, 1994).

The raw source (Design patterns.md) is primarily visual (slides). Images are at: ../raw/Design patterns_files/media/

Categories

Creational — how objects are created

PatternPurpose
Factory MethodDelegate instantiation to subclasses
Abstract FactoryCreate families of related objects
BuilderConstruct complex objects step by step
SingletonSingle instance per application
PrototypeClone existing objects

Structural — how objects are composed

PatternPurpose
AdapterTranslate one interface to another
DecoratorAdd behaviour to objects dynamically
FacadeSimplified interface to a subsystem
CompositeTree structures of objects
ProxyPlaceholder for another object

Behavioural — how objects communicate

PatternPurpose
ObserverNotify dependents of state changes
StrategySwap algorithms at runtime
CommandEncapsulate requests as objects
IteratorTraverse collections without exposing internals
Template MethodDefine skeleton of algorithm in base class
Chain of ResponsibilityPass request along a chain of handlers

Null Object pattern

Problem: Methods returning null force callers to guard with if (result != null) everywhere. Information about why it’s null is lost.

Solution: Return a “null object” — an instance that implements the interface but does nothing (or carries error information).

public interface IPurchaseReport
{
    IPurchaseReport CreateFailedPurchase();
    IPurchaseReport CreateNotSignedIn();
    IPurchaseReport CreateNotRegistered(string username);
    IPurchaseReport CreateProductNotFound(string username, string productName);
    IPurchaseReport CreateNotEnoughMoney(string username, string productName, decimal price);
    IPurchaseReport CreateReport(string username, string productName, decimal price);
}

Benefits:

  • Simplifies control flow on the caller — no null checks
  • Special Case carries additional information back to the caller
  • Control flow is flat — all operations flow through same steps
  • Information required to complete operation is carried by the returned object

![Null Object pattern diagram](../../raw/Design patterns_files/media/image5.png)


Special Case pattern

A variant of Null Object where the returned object carries meaningful error context.

Example: instead of null when a user isn’t logged in, return a NotLoggedInReport that implements IPurchaseReport and contains the reason.

Result path through layers:

As execution progresses through layers (Presentation → Application → Domain → Repository), each layer can detect an error and return a special case object — carrying more and more information as it travels back up.

![Special Case path diagram](../../raw/Design patterns_files/media/image2.png)


Factory pattern

Encapsulates object creation. The IPurchaseReportFactory example:

// Wired up at composition root
var ui = new ApplicationServices(
    new DomainServices(
        new UserRepository(),
        new PurchaseReportFactory(),
        new ProductRepository()
    ),
    reportFactory
);

Dependency Injection

See Dependency-Injection for full coverage. DI is the mechanism that makes patterns like Factory and Strategy composable.


See also