Skip to main content
CleanCodeMastery

Abstract Factory Pattern: One Order, One Matching Thali

Understand the Abstract Factory design pattern through an Indian wedding catering story, with simple TypeScript and Python code, diagrams, and practice.

24 min read Updated June 11, 2026beginner
abstract factorydesign patternscreationaltypescriptoopproduct families

๐ŸŽฏ The story of Meena Tai's wedding catering

Let us begin with a busy wedding morning in Nashik.

Meena Tai runs Swaad Caterers. Families book her for weddings, and she offers complete meal styles. A customer can choose a Gujarati thali or a South Indian thali. Whichever style is chosen, every guest's plate gets three things: a starter, a main course, and a sweet.

Here is the important rule of her kitchen: everything on one plate must belong to the same style. If the family books a Gujarati thali, the plate gets dhokla, then thepla with shaak, and shrikhand at the end. If they book South Indian, the plate gets medu vada, then dosa with sambar, and payasam to finish.

Now imagine a disaster. It is the Shah family wedding. Five hundred guests. Meena Tai's newest helper, a nervous young man named Bunty, is running between counters with plates. In the rush, Bunty puts payasam on a Gujarati plate. The grandmother of the bride โ€” everyone calls her Dadi ji โ€” notices in two seconds flat. "Beta, this sweet does not match the thali!" Bunty turns red. The mistake is small, but in catering, matching matters. The whole set must belong together.

That night, Meena Tai cannot sleep. She thinks: the problem is not Bunty. The problem is that my kitchen allows mixing. So she makes a smart system. She does not let helpers pick dishes one by one from open trays. Instead, each wedding gets one counter โ€” either the Gujarati counter or the South Indian counter. A helper simply goes to the counter and asks: "one starter, please", "one main, please", "one sweet, please". The helper never names the dish. The counter guarantees that everything it hands out belongs to one matching style.

Choose the counter once, and a thousand plates come out perfectly matched. It becomes impossible to mix styles, because only one counter is in the room. Even Bunty cannot make the payasam mistake now โ€” there is simply no payasam at the Gujarati counter.

Figure 1: The Shah wedding, before and after Meena Tai's one-counter system

The counter is a factory that produces a whole family of matching products. That is exactly the Abstract Factory pattern. Keep this catering story with you โ€” Meena Tai, Bunty, and Dadi ji will walk with us through every section, and we will write their kitchen in code soon.

๐Ÿ’ก What is the Abstract Factory pattern?

Abstract Factory is a creational design pattern. Its job: create families of related objects without naming their concrete classes in your main code.

Let us unpack that slowly, with the kitchen in front of us:

  • A product kind is a role on the plate: starter, main course, sweet.
  • A family (also called a variant) is a style: Gujarati or South Indian.
  • The abstract factory is an interface that says: "Any counter must be able to give a starter, a main, and a sweet." It promises what can be made, not which version.
  • A concrete factory implements that interface for one family. The Gujarati counter gives dhokla, thepla-shaak, and shrikhand. The South Indian counter gives medu vada, dosa-sambar, and payasam.

Your main code (the client โ€” that is Bunty) holds a reference to the abstract factory only. It asks for "a starter" and trusts the answer. It never writes new Dhokla() anywhere.

This pattern also comes from the Gang of Four book (1994), where it is sometimes called a Kit or Toolkit, because the factory hands you a complete kit of matching parts.

Figure 2: The whole Abstract Factory idea on one mind map
๐Ÿ’ก

One-line summary: Abstract Factory = choose the family once, and one factory object gives you every matching member of that family. In kitchen language: pick the counter once, and every plate matches.

Compare with the Factory Method pattern you learned earlier: Sharma Aunty's branches created one product (the vehicle) through one overridable method. Meena Tai's counters create a whole set of products that must fit together. The emphasis is on the word family.

College corner: in GoF terms, Abstract Factory raises the level of abstraction one step above Factory Method. Factory Method varies one object via inheritance (subclass overrides a method). Abstract Factory varies a coherent set via object composition (the client is configured with a factory object). The matching guarantee is enforced by the type system: a GujaratiThaliFactory has no member that can return a South Indian product, so cross-family invariants hold statically, not by runtime discipline.

โš ๏ธ The problem it solves

Let us feel the pain first. Suppose Meena Tai's nephew codes Swaad Caterers without the pattern. Every dish decision becomes an if-else on the style:

// BAD CODE: style checks scattered through the kitchen
function serveGuestPlate(style: string): void {
  // starter
  if (style === "gujarati") {
    console.log("Serving dhokla");
  } else {
    console.log("Serving medu vada");
  }
 
  // main course
  if (style === "gujarati") {
    console.log("Serving thepla with shaak");
  } else {
    console.log("Serving dosa with sambar");
  }
 
  // sweet
  if (style === "gujarati") {
    console.log("Serving shrikhand");
  } else {
    console.log("Serving payasam");
  }
}

This already looks repetitive with two styles and three dishes. Now scale it like real life:

  1. A new family arrives. Meena Tai adds a Punjabi thali for a Chandigarh family. We must hunt down every if-else in the whole codebase and add a branch. Miss one spot, and a Punjabi wedding gets shrikhand by accident โ€” exactly the mixed-plate disaster from our story, but now hidden in code.
  2. Nothing enforces matching. The compiler is perfectly happy if one function serves a Gujarati starter and another serves a South Indian sweet to the same guest. The bug appears only at the wedding, at runtime, in front of Dadi ji.
  3. Creation logic pollutes business logic. Code that should be about serving guests is crowded with which dish belongs to which style decisions, repeated everywhere.
Figure 3: Scattered style checks โ€” every dish, every function asks the same question, and a new style must touch them all

And where does the pain actually land when this code grows? Mostly in two places: hunting style checks during every change, and firefighting mixed-family bugs that only appear at runtime.

Figure 4: How maintenance time gets eaten in a no-pattern kitchen codebase

What we really want is one decision point: choose the style once at booking time, and after that, every dish created automatically belongs to the correct, mutually matching family. That is the promise of Abstract Factory โ€” Meena Tai's one-counter rule, written in types.

๐Ÿ› ๏ธ How Abstract Factory works, step by step

Let us build the solution slowly. There is a neat trick for planning: draw a matrix (a table) first. Meena Tai actually has this matrix painted on her kitchen wall:

Gujarati familySouth Indian family
StarterDhoklaMedu Vada
Main courseThepla with ShaakDosa with Sambar
SweetShrikhandPayasam

The rows are product kinds. The columns are families. Every cell is one concrete class. Now follow these steps:

  1. One interface per row. Create abstract products: Starter, MainCourse, Sweet. Every dish in that row implements its row's interface.
  2. One abstract factory with one method per row. Create ThaliFactory with createStarter(), createMainCourse(), createSweet(). Each method returns the abstract product type.
  3. One concrete factory per column. GujaratiThaliFactory returns the Gujarati cells; SouthIndianThaliFactory returns the South Indian cells. Each concrete factory produces dishes from exactly one column โ€” that is how matching is guaranteed.
  4. Write the client against abstractions only. The serving code receives a ThaliFactory (usually through its constructor) and works only with Starter, MainCourse, and Sweet references. Bunty only knows roles, never dish names.
  5. Select the concrete factory once. At booking time (the program's start), read the customer's choice and create the matching factory. Pass it down. Nothing downstream ever learns which family it is using.
Figure 5: The participants โ€” two concrete factories, each producing one full matching column of products

(The MainCourse row is left out of the diagram only to keep it readable โ€” it follows the exact same shape.)

โ„น๏ธ

Notice the guarantee: a GujaratiThaliFactory object simply has no code path that can produce payasam. Mixing families stops being a discipline problem and becomes structurally impossible. The type system does the policing, so Bunty can relax.

Here is one guest being served, as a conversation in time. Bunty (the client) talks only to the counter, and the counter answers with matching dishes:

Figure 6: Serving one guest โ€” the client asks the factory for each role, never naming a dish

College corner: each individual method on the factory (createStarter()) is itself a Factory Method. Abstract Factory is therefore best understood as a bundle of Factory Methods grouped under one invariant: "all of my outputs belong to one variant." When you see a class whose only job is a coherent set of createX() methods, you are looking at this pattern even if nobody named it.

๐Ÿงช Real-life code example

Now let us write Swaad Caterers fully in TypeScript. We will go section by section, exactly mirroring the wall matrix.

Section 1: the abstract products. One interface per row of our matrix.

// ---------- ABSTRACT PRODUCTS (the rows) ----------
interface Starter {
  name: string;
  serve(): void;
}
 
interface MainCourse {
  name: string;
  serve(): void;
}
 
interface Sweet {
  name: string;
  serve(): void;
}

Section 2: the concrete products. Every cell of the matrix becomes a small class.

// ---------- GUJARATI FAMILY ----------
class Dhokla implements Starter {
  name = "dhokla";
  serve(): void {
    console.log("  Starter: soft dhokla with green chutney.");
  }
}
 
class TheplaShaak implements MainCourse {
  name = "thepla with shaak";
  serve(): void {
    console.log("  Main: thepla with bateta nu shaak.");
  }
}
 
class Shrikhand implements Sweet {
  name = "shrikhand";
  serve(): void {
    console.log("  Sweet: chilled kesar shrikhand.");
  }
}
 
// ---------- SOUTH INDIAN FAMILY ----------
class MeduVada implements Starter {
  name = "medu vada";
  serve(): void {
    console.log("  Starter: crispy medu vada with coconut chutney.");
  }
}
 
class DosaSambar implements MainCourse {
  name = "dosa with sambar";
  serve(): void {
    console.log("  Main: paper dosa with hot sambar.");
  }
}
 
class Payasam implements Sweet {
  name = "payasam";
  serve(): void {
    console.log("  Sweet: warm semiya payasam.");
  }
}

Section 3: the abstract factory and the concrete factories. This is the heart of the pattern โ€” the counters from our story.

// ---------- ABSTRACT FACTORY ----------
// "Any counter must be able to give these three things."
interface ThaliFactory {
  styleName: string;
  createStarter(): Starter;
  createMainCourse(): MainCourse;
  createSweet(): Sweet;
}
 
// ---------- CONCRETE FACTORIES (the columns) ----------
class GujaratiThaliFactory implements ThaliFactory {
  styleName = "Gujarati";
  createStarter(): Starter {
    return new Dhokla();
  }
  createMainCourse(): MainCourse {
    return new TheplaShaak();
  }
  createSweet(): Sweet {
    return new Shrikhand();
  }
}
 
class SouthIndianThaliFactory implements ThaliFactory {
  styleName = "South Indian";
  createStarter(): Starter {
    return new MeduVada();
  }
  createMainCourse(): MainCourse {
    return new DosaSambar();
  }
  createSweet(): Sweet {
    return new Payasam();
  }
}

Read GujaratiThaliFactory again slowly. Every method returns a dish from the same column. There is no way for this class to hand out payasam. That is the matching guarantee, written in plain code. Dadi ji could read this class and smile.

Section 4: the client. The serving crew works only with abstractions.

// ---------- CLIENT ----------
class WeddingService {
  // The factory comes in through the constructor.
  // The crew never knows WHICH concrete factory it is.
  constructor(private factory: ThaliFactory) {}
 
  serveGuest(guestName: string): void {
    console.log(`Plate for ${guestName} (${this.factory.styleName} thali):`);
    const starter = this.factory.createStarter();
    const main = this.factory.createMainCourse();
    const sweet = this.factory.createSweet();
 
    starter.serve();
    main.serve();
    sweet.serve();
  }
}

Look how clean serveGuest is. No if. No style strings. No dish names. Only roles: starter, main, sweet. This is Bunty after the new system โ€” calm, fast, and unable to make the payasam mistake.

Section 5: the booking desk โ€” the single decision point.

// ---------- COMPOSITION ROOT ----------
// The ONLY place that knows concrete factories.
function bookWedding(style: "gujarati" | "south-indian"): WeddingService {
  const factory: ThaliFactory =
    style === "gujarati"
      ? new GujaratiThaliFactory()
      : new SouthIndianThaliFactory();
  return new WeddingService(factory);
}
 
const shahWedding = bookWedding("gujarati");
shahWedding.serveGuest("Dadi ji");
shahWedding.serveGuest("Rohan");
 
const iyerWedding = bookWedding("south-indian");
iyerWedding.serveGuest("Paati");

Running this prints:

Plate for Dadi ji (Gujarati thali):
  Starter: soft dhokla with green chutney.
  Main: thepla with bateta nu shaak.
  Sweet: chilled kesar shrikhand.
Plate for Rohan (Gujarati thali):
  Starter: soft dhokla with green chutney.
  Main: thepla with bateta nu shaak.
  Sweet: chilled kesar shrikhand.
Plate for Paati (South Indian thali):
  Starter: crispy medu vada with coconut chutney.
  Main: paper dosa with hot sambar.
  Sweet: warm semiya payasam.

Every plate is perfectly matched. Dadi ji is happy. Bunty gets a raise.

Now the magic moment: Meena Tai launches the Punjabi thali. What changes in the old code? Nothing. We only add one new column:

class PaneerTikka implements Starter {
  name = "paneer tikka";
  serve(): void {
    console.log("  Starter: smoky paneer tikka.");
  }
}
 
class CholeBhature implements MainCourse {
  name = "chole bhature";
  serve(): void {
    console.log("  Main: chole with fluffy bhature.");
  }
}
 
class GajarHalwa implements Sweet {
  name = "gajar halwa";
  serve(): void {
    console.log("  Sweet: hot gajar ka halwa with ghee.");
  }
}
 
class PunjabiThaliFactory implements ThaliFactory {
  styleName = "Punjabi";
  createStarter(): Starter {
    return new PaneerTikka();
  }
  createMainCourse(): MainCourse {
    return new CholeBhature();
  }
  createSweet(): Sweet {
    return new GajarHalwa();
  }
}

WeddingService does not change by even one character. Only the booking desk gets one more option. This is the Open/Closed Principle again: new family = new code, not edited code.

๐Ÿ“Š The same idea in Python

The pattern is not tied to one language. Here is a compact Python version of the same kitchen:

from abc import ABC, abstractmethod
 
 
# ----- abstract products -----
class Starter(ABC):
    @abstractmethod
    def serve(self) -> None: ...
 
 
class Sweet(ABC):
    @abstractmethod
    def serve(self) -> None: ...
 
 
# ----- concrete products -----
class Dhokla(Starter):
    def serve(self) -> None:
        print("  Starter: dhokla")
 
 
class MeduVada(Starter):
    def serve(self) -> None:
        print("  Starter: medu vada")
 
 
class Shrikhand(Sweet):
    def serve(self) -> None:
        print("  Sweet: shrikhand")
 
 
class Payasam(Sweet):
    def serve(self) -> None:
        print("  Sweet: payasam")
 
 
# ----- abstract factory -----
class ThaliFactory(ABC):
    @abstractmethod
    def create_starter(self) -> Starter: ...
 
    @abstractmethod
    def create_sweet(self) -> Sweet: ...
 
 
# ----- concrete factories -----
class GujaratiThaliFactory(ThaliFactory):
    def create_starter(self) -> Starter:
        return Dhokla()
 
    def create_sweet(self) -> Sweet:
        return Shrikhand()
 
 
class SouthIndianThaliFactory(ThaliFactory):
    def create_starter(self) -> Starter:
        return MeduVada()
 
    def create_sweet(self) -> Sweet:
        return Payasam()
 
 
# ----- client -----
def serve_guest(factory: ThaliFactory) -> None:
    factory.create_starter().serve()
    factory.create_sweet().serve()
 
 
serve_guest(GujaratiThaliFactory())   # dhokla + shrikhand, always matched
serve_guest(SouthIndianThaliFactory())  # medu vada + payasam, always matched

Same shape, different language: interfaces for rows, one factory class per column, a client that only sees abstractions.

And one small C# variation that real teams love โ€” the testing family. In production, the app receives the real factory; in tests, it receives a fake factory whose whole family is made of harmless fakes:

public interface IKitchenFactory
{
    IOven CreateOven();
    IBillPrinter CreatePrinter();
}
 
// Production column: real machines.
public class RealKitchenFactory : IKitchenFactory
{
    public IOven CreateOven() => new GasOven();
    public IBillPrinter CreatePrinter() => new ThermalPrinter();
}
 
// Test column: everything fake, everything safe.
public class FakeKitchenFactory : IKitchenFactory
{
    public IOven CreateOven() => new RecordingFakeOven();
    public IBillPrinter CreatePrinter() => new InMemoryPrinter();
}
 
// The client never knows which world it lives in:
var kitchen = new KitchenService(new FakeKitchenFactory());

Swap one factory, and you swap the entire world the client lives in โ€” real or fake, but always internally consistent. That is the family guarantee doing double duty as a testing tool.

๐Ÿ’ก Where you see it in real software

Abstract Factory quietly powers a lot of famous software:

  • Java's DocumentBuilderFactory.newInstance() in the javax.xml.parsers package is a textbook example. You ask the abstract factory for a DocumentBuilder, and it returns the right concrete XML-parsing family for your environment โ€” your code never names the parser implementation. Its sibling TransformerFactory.newInstance() works the same way.
  • .NET's DbProviderFactory (in System.Data.Common) is a beautiful family factory. One factory object gives you CreateConnection(), CreateCommand(), and CreateDataAdapter() โ€” and all of them belong to the same database family (all SQL Server pieces, or all MySQL pieces). It would be a disaster to pair a SQL Server connection with a MySQL command; the factory makes that impossible, exactly like our thali counter.
  • Cross-platform UI toolkits use the pattern for look-and-feel: choose the platform family once, and every widget created afterwards โ€” button, checkbox, scrollbar โ€” automatically matches that platform's style. This was the original motivating example in the GoF book.
  • Test code vs production code. Many apps pass a "real services" factory in production and a "fake services" factory in tests, as in our C# snippet above. Same client code, two consistent families.

For deeper study, see the worked examples in iluwatar/java-design-patterns (a kingdom example with elf and orc families), the short Python version in faif/python-patterns, and the illustrated guide on Refactoring Guru.

๐ŸŽฏ When to use it and when not to

First, find your project on this map. Swaad Caterers sits high and right: several product kinds that must match, and new families keep arriving.

Figure 7: Should your project use Abstract Factory? Find your spot on the map

Then confirm with the table:

SituationUse Abstract Factory?Why
You have several products that must be used together as a matching setโœ… YesThe factory makes mixing families impossible
You expect new families (new themes, new platforms, new menu styles)โœ… YesA new family is just one new factory class plus its products
You want all concrete-class knowledge in one startup spotโœ… YesOnly the composition root names concrete factories
You need real vs fake object sets for testingโœ… YesSwap one factory, swap the whole world
You have only one product kindโŒ NoA single Factory Method is enough โ€” no family exists
Product kinds change often (new rows in the matrix)โŒ NoEvery new kind forces edits in all concrete factories
The program is small and variants will never appearโŒ NoThe extra interfaces and classes are pure overhead

That second โŒ row deserves attention. Remember the wall matrix: the pattern loves new columns (families) but hates new rows (product kinds). The chart below shows both directions for our kitchen with three families on board:

Figure 8: The two directions of change โ€” adding a family is cheap, adding a product kind touches every factory

Adding the Punjabi family with the pattern touched one existing file (the booking desk). But adding a createDrink() row forces Gujarati, South Indian, and Punjabi factories โ€” plus the interface โ€” to all change at once. Plan your rows carefully at the start, the way Meena Tai planned her wall matrix before painting it.

College corner: this asymmetry is a classic instance of the expression problem: class hierarchies make it easy to add new variants but hard to add new operations, while functional sum types do the opposite. Abstract Factory deliberately optimizes the variant axis. If your domain grows along the kind axis instead, consider visitor-style designs, or accept periodic interface churn with default implementations to soften the blow.

๐Ÿ› ๏ธ Lifecycle of one wedding booking

Watch where the big decision happens: exactly once, at booking. After the FactoryChosen state, the kitchen never asks "which style?" again โ€” it just serves.

Figure 9: The life of a booking โ€” the family is decided once, then a thousand plates flow without questions

The self-loop on ServingGuests is the beauty of the pattern: hundreds of creations happen there, and not one of them re-asks the family question. Compare this with the no-pattern flowchart in Figure 3, where every single plate re-asked it three times.

๐Ÿ“Š Compare with cousins

PatternCreatesStrengthWatch out for
Abstract FactoryA family of related productsGuarantees the set matchesNew product kinds are costly
Factory MethodOne productSimple; great starting pointOne method, one product only
BuilderOne complex product, step by stepReadable assembly of big objectsNot about families at all
PrototypeA copy of an existing objectNo subclassing neededNeeds a good clone operation
SingletonOne single shared instanceOften used for the concrete factoryDifferent purpose entirely

A few useful relationships to remember, in story language:

  • Each method inside an Abstract Factory (createStarter(), createSweet()) is usually implemented as a Factory Method. So Meena Tai's counter is really a team of Sharma Aunty's tricks working together.
  • Designs often start with one Factory Method and grow into an Abstract Factory when more related products appear. Aunty's tiffin shop could one day become a catering counter.
  • A concrete factory is often made a Singleton, because one Gujarati counter is enough for the whole wedding.
  • Builder answers a different question: not "which family?" but "how do I assemble this one complicated object?" An Abstract Factory can even return ready-made builders โ€” a counter that hands you order slips.

โš ๏ธ Common mistakes students make

โš ๏ธ

Mistake 1: Asking two different factories for one plate. If the client creates new GujaratiThaliFactory() in one function and new SouthIndianThaliFactory() in another, you have re-created Bunty's payasam disaster with extra steps. The factory must be chosen once and passed down โ€” usually through a constructor.

โš ๏ธ

Mistake 2: Returning concrete types from the factory methods. If createStarter() declares its return type as Dhokla instead of Starter, client code starts depending on the concrete class and the decoupling evaporates. Factory methods must return the abstract product type.

โš ๏ธ

Mistake 3: Confusing it with Factory Method. "I have a factory class, so it must be Abstract Factory" โ€” not necessarily! If it creates just one product, it is a Factory Method (or a simple factory). The word abstract here refers to a factory interface with multiple creation methods producing a family.

๐Ÿšจ

Mistake 4: Designing the matrix lazily. Students often start with one product kind, then keep bolting on createX() methods every week. Each addition breaks every concrete factory. Sit down first, list your rows (kinds) and columns (families), and only then write the interfaces โ€” paint the wall matrix before opening the kitchen.

The same list as a quick-scan table:

MistakeWhat it looks likeThe fix
Two factories for one plateDifferent new XFactory() calls in different functionsChoose once at the composition root, pass it down
Concrete return typescreateStarter(): DhoklaAlways return the abstract product type
Wrong pattern nameCalling any factory class an Abstract FactoryFamily of methods = Abstract Factory; one method = Factory Method
Lazy matrixNew createX() bolted on weeklyPlan rows and columns before writing interfaces

๐Ÿงช Quick revision box

+=================================================================+
|             ABSTRACT FACTORY - QUICK REVISION                   |
+=================================================================+
|  IDEA       : One factory interface creates a whole FAMILY      |
|               of matching products. Pick the family once.       |
|  ALSO CALLED: Kit / Toolkit (GoF, 1994)                         |
|-----------------------------------------------------------------|
|  THE MATRIX                                                     |
|     rows    = product kinds  (Starter, Main, Sweet)             |
|     columns = families       (Gujarati, South Indian, Punjabi)  |
|     one interface per ROW, one concrete factory per COLUMN      |
|-----------------------------------------------------------------|
|  GOLDEN RULES                                                   |
|    1. Client sees ONLY abstract factory + abstract products.    |
|    2. One factory = one family. Mixing becomes impossible.      |
|    3. New family  = cheap (add a column).                       |
|       New kind    = costly (every factory changes).             |
|-----------------------------------------------------------------|
|  REAL LIFE  : DocumentBuilderFactory (Java XML),                |
|               DbProviderFactory (.NET), UI look-and-feel kits   |
|  REMEMBER   : "One counter, one matching thali."                |
+=================================================================+

๐ŸŽฏ Practice exercise

Your turn at the counter! Try these tasks:

  1. Add the Bengali thali. Create BegunBhaja (starter), LuchiAlurDom (main), and Rosogolla (sweet), plus a BengaliThaliFactory. Prove to yourself that WeddingService needed zero changes.
  2. Festival decoration kits. A school decorates for annual day in two themes: Traditional (marigold garlands, diya lamps, rangoli) and Modern (balloon arches, LED strips, poster art). Model Garland, Light, and FloorArt as product kinds and build two concrete factories. Write a DecorationCrew client that decorates one classroom using whichever factory it receives.
  3. Draw before you code. For exercise 2, draw your own wall matrix (rows and columns) and your own versions of Figure 5 and Figure 9. Mark the single state where the theme is chosen.
  4. Think and write (no code). Meena Tai wants to add a fourth item to every thali: a welcome drink. Explain in 4-5 sentences exactly which files must change, why this is the "expensive direction" of the pattern, and how planning the matrix earlier would have helped.
  5. College corner challenge. Build the FakeKitchenFactory idea for exercise 2: a test family whose products record what was asked of them. Write one unit test that proves DecorationCrew decorates a classroom correctly without touching any real decoration class.

Excellent work! You now know how Meena Tai guarantees matching families. Next, visit Iqbal Chacha's tailor shop and learn how to assemble one big, complicated object step by step with the Builder pattern.

Frequently asked questions

What does 'family of products' actually mean?
It means a group of different objects that are designed to be used together and must match each other. For example, a Gujarati starter, a Gujarati main course, and a Gujarati sweet form one family. A Windows button and a Windows checkbox form another family. The factory guarantees you never mix items from two families.
How is Abstract Factory different from Factory Method?
Factory Method has one creation method and makes one product. Abstract Factory is an interface with several creation methods, one for each product kind, and all of them return products from the same matching family. In fact, each method inside an Abstract Factory is usually itself a Factory Method.
Where do I choose which concrete factory to use?
In exactly one place, usually at the start of the program. You read a setting (like the menu style or the operating system), create the matching concrete factory once, and pass it to the rest of the code. After that point, no other code knows which family is in use.
What is the biggest weakness of Abstract Factory?
Adding a new kind of product is painful. If you add a createDrink method to the factory interface, every single concrete factory must be updated to implement it. The pattern is friendly to new families but unfriendly to new product kinds.
Is Abstract Factory overkill for small programs?
Often, yes. The pattern adds many interfaces and classes. If you have only one product variant, or your products do not need to match each other as a set, a simple Factory Method or plain constructors will keep your code shorter and easier to read.

Further reading

Related Lessons