Architecture & Patterns110 min total · 26 parts
ACID, SOLID, and Design Patterns: A Complete Software Design Reference
Part 13 of 26 · ~2 min
Creational Patterns: Factory Method and Abstract Factory
Every pattern in this next group answers a version of the same question: who is responsible for constructing an object, and how much does the code on the receiving end need to know about the concrete class that construction actually produced?
Factory Method hands the question of which concrete class to instantiate off to a dedicated method somewhere else in the hierarchy, so the caller never has to depend on anything more specific than an abstraction:
public interface IShiftNotifier { void Send(string message); }
public class SmsShiftNotifier : IShiftNotifier { public void Send(string message) { } }
public class PushShiftNotifier : IShiftNotifier { public void Send(string message) { } }
public abstract class NotifierFactory
{
public abstract IShiftNotifier Create();
}
public class SmsNotifierFactory : NotifierFactory
{
public override IShiftNotifier Create() => new SmsShiftNotifier();
}
public class PushNotifierFactory : NotifierFactory
{
public override IShiftNotifier Create() => new PushShiftNotifier();
}
// Calling code depends on NotifierFactory, never on SmsShiftNotifier or PushShiftNotifier directly.
void Notify(NotifierFactory factory, string message) => factory.Create().Send(message);
Abstract Factory solves a related but bigger problem: instead of one object, it hands back several objects that have to belong together, guaranteed, through a single interface that creates all of them. Each of ShiftDesk's sites needs a matched pair of check-in materials — a sign-in sheet and a name badge — and having the shelter's badge stock end up printed next to the food bank's sign-in sheet at the wrong table is precisely the mix-up this pattern makes structurally impossible:
public interface ISignInSheet { void Render(); }
public interface INameBadge { void Render(); }
public interface ISiteKitFactory
{
ISignInSheet CreateSignInSheet();
INameBadge CreateNameBadge();
}
public class ShelterKitFactory : ISiteKitFactory
{
public ISignInSheet CreateSignInSheet() => new ShelterSignInSheet();
public INameBadge CreateNameBadge() => new ShelterNameBadge();
}
public class FoodBankKitFactory : ISiteKitFactory
{
public ISignInSheet CreateSignInSheet() => new FoodBankSignInSheet();
public INameBadge CreateNameBadge() => new FoodBankNameBadge();
}
// Given one factory, every printed material it produces is guaranteed to match one site.
void PrepareFrontDesk(ISiteKitFactory factory)
{
var sheet = factory.CreateSignInSheet();
var badge = factory.CreateNameBadge();
}
If you only remember one contrast between the two, make it this: Factory Method hands off the decision for a single object type, and it does that through inheritance — a subclass decides which concrete class gets instantiated. Abstract Factory hands off the decision for a coordinated set of object types at once, and it does that through composition — one object bundling several creation methods whose outputs are only meant to be used together, never mixed with another factory's outputs.