Abstract Factory⚓︎
"I want a whole set of products that match each other."
Characteristics⚓︎
- families of related products
- composition over inheritance
- switch factory = switch entire product families
eg: windows ui / mac os ui⚓︎
- windows factory -> windows button + windows checkbox
- mac os factory -> mac os button + mac os checkbox
Hands dirty - "Level Theme factory"⚓︎
We want to create level themes in a game.
Each theme has a matching set of Enemy and Obstacle.
ForestThemeFactorycreatesGoblin,forest monsters,forest weaponsandTreeCaveThemeFactorycreatesTroll,cave monsters,cave weaponsandCactusIceThemeFactorycreatesYeti,ice monsters,ice weaponsandIceberg
Implementation
using System;
public interface IEnemy { string Name { get; } }
public interface IObstacle { string Name { get; } }
public interface IWeapon { string Name { get; } }
public interface ILevelThemeFactory
{
IEnemy CreateEnemy();
IEnemy CreateMinion();
IObstacle CreateObstacle();
IWeapon CreateWeapon();
}
// Forest
public class Goblin : IEnemy { public string Name => "Goblin"; }
public class ForestMonster : IEnemy { public string Name => "Forest Monster"; }
public class Tree : IObstacle { public string Name => "Tree"; }
public class ForestWeapon : IWeapon { public string Name => "Forest Weapon"; }
public class ForestThemeFactory : ILevelThemeFactory
{
public IEnemy CreateEnemy() => new Goblin();
public IEnemy CreateMinion() => new ForestMonster();
public IObstacle CreateObstacle() => new Tree();
public IWeapon CreateWeapon() => new ForestWeapon();
}
// Cave
public class Troll : IEnemy { public string Name => "Troll"; }
public class CaveMonster : IEnemy { public string Name => "Cave Monster"; }
public class CaveWeapon : IWeapon { public string Name => "Cave Weapon"; }
public class Cactus : IObstacle { public string Name => "Cactus"; }
public class CaveThemeFactory : ILevelThemeFactory
{
public IEnemy CreateEnemy() => new Troll();
public IEnemy CreateMinion() => new CaveMonster();
public IObstacle CreateObstacle() => new Cactus();
public IWeapon CreateWeapon() => new CaveWeapon();
}
// Ice
public class Yeti : IEnemy { public string Name => "Yeti"; }
public class IceMonster : IEnemy { public string Name => "Ice Monster"; }
public class IceWeapon : IWeapon { public string Name => "Ice Weapon"; }
public class Iceberg : IObstacle { public string Name => "Iceberg"; }
public class IceThemeFactory : ILevelThemeFactory
{
public IEnemy CreateEnemy() => new Yeti();
public IEnemy CreateMinion() => new IceMonster();
public IObstacle CreateObstacle() => new Iceberg();
public IWeapon CreateWeapon() => new IceWeapon();
}
class Program
{
static void Main()
{
ILevelThemeFactory factory = new ForestThemeFactory();
var boss = factory.CreateEnemy();
var minion = factory.CreateMinion();
var obstacle = factory.CreateObstacle();
var weapon = factory.CreateWeapon();
Console.WriteLine($"{boss.Name}, {minion.Name}, {obstacle.Name}, {weapon.Name}");
}
}
#include <iostream>
#include <memory>
#include <string>
struct IEnemy { virtual std::string name() const = 0; virtual ~IEnemy() = default; };
struct IObstacle { virtual std::string name() const = 0; virtual ~IObstacle() = default; };
struct IWeapon { virtual std::string name() const = 0; virtual ~IWeapon() = default; };
struct ILevelThemeFactory {
virtual std::shared_ptr<IEnemy> createEnemy() = 0;
virtual std::shared_ptr<IEnemy> createMinion() = 0;
virtual std::shared_ptr<IObstacle> createObstacle() = 0;
virtual std::shared_ptr<IWeapon> createWeapon() = 0;
virtual ~ILevelThemeFactory() = default;
};
// Forest
struct Goblin : IEnemy { std::string name() const override { return "Goblin"; } };
struct ForestMonster : IEnemy { std::string name() const override { return "Forest Monster"; } };
struct Tree : IObstacle { std::string name() const override { return "Tree"; } };
struct ForestWeapon : IWeapon { std::string name() const override { return "Forest Weapon"; } };
struct ForestThemeFactory : ILevelThemeFactory {
std::shared_ptr<IEnemy> createEnemy() override { return std::make_shared<Goblin>(); }
std::shared_ptr<IEnemy> createMinion() override { return std::make_shared<ForestMonster>(); }
std::shared_ptr<IObstacle> createObstacle() override { return std::make_shared<Tree>(); }
std::shared_ptr<IWeapon> createWeapon() override { return std::make_shared<ForestWeapon>(); }
};
// Cave
struct Troll : IEnemy { std::string name() const override { return "Troll"; } };
struct CaveMonster : IEnemy { std::string name() const override { return "Cave Monster"; } };
struct Cactus : IObstacle { std::string name() const override { return "Cactus"; } };
struct CaveWeapon : IWeapon { std::string name() const override { return "Cave Weapon"; } };
struct CaveThemeFactory : ILevelThemeFactory {
std::shared_ptr<IEnemy> createEnemy() override { return std::make_shared<Troll>(); }
std::shared_ptr<IEnemy> createMinion() override { return std::make_shared<CaveMonster>(); }
std::shared_ptr<IObstacle> createObstacle() override { return std::make_shared<Cactus>(); }
std::shared_ptr<IWeapon> createWeapon() override { return std::make_shared<CaveWeapon>(); }
};
// Ice
struct Yeti : IEnemy { std::string name() const override { return "Yeti"; } };
struct IceMonster : IEnemy { std::string name() const override { return "Ice Monster"; } };
struct Iceberg : IObstacle { std::string name() const override { return "Iceberg"; } };
struct IceWeapon : IWeapon { std::string name() const override { return "Ice Weapon"; } };
struct IceThemeFactory : ILevelThemeFactory {
std::shared_ptr<IEnemy> createEnemy() override { return std::make_shared<Yeti>(); }
std::shared_ptr<IEnemy> createMinion() override { return std::make_shared<IceMonster>(); }
std::shared_ptr<IObstacle> createObstacle() override { return std::make_shared<Iceberg>(); }
std::shared_ptr<IWeapon> createWeapon() override { return std::make_shared<IceWeapon>(); }
};
int main() {
std::shared_ptr<ILevelThemeFactory> factory = std::make_shared<ForestThemeFactory>();
auto boss = factory->createEnemy();
auto minion = factory->createMinion();
auto obstacle = factory->createObstacle();
auto weapon = factory->createWeapon();
std::cout << boss->name() << ", " << minion->name() << ", " << obstacle->name() << ", " << weapon->name() << "\n";
}
Diff: Abstract Factory v.s. Factory Method⚓︎
-
Factory Method:
- Creates one product.
- Relies on subclassing and overriding a factory method to decide which concrete product to create.
- Often used when a class cannot anticipate the concrete type of object it needs to create.
-
Abstract Factory:
- Creates families of related or dependent products.
- Relies on object composition: the client holds a concrete factory to create consistent product families.
- Often used when a system needs to be independent of product creation details and ensure consistency among related products.
Abstract Factory ≠ “Factory Method × N”
Abstract Factory is not simply a collection of multiple Factory Methods.
The Factory Method focuses on deferring the creation of a single product,whereas the Abstract Factory focuses on enforcing consistency among multiple related products.
The true dividing line between the two lies in whether variation is bound or independent.
-
In the
Factory Methodpattern, each product varies independently. Which concrete product is created is determined by the subclass, and changes to one product do not affect others. -
In contrast, with the
Abstract Factorypattern, once a concrete factory is selected,the variations of multiple products become bound together as a group.They share the same creation rules and semantic context.
By encapsulating the creation of a related set of products within a single factory object, the Abstract Factory proactively prevents invalid combinations, thereby ensuring semantic consistency and overall correctness of the product family at the system level.

