Creational · 2 of 5
Abstract Factory
Abstract Factory is a creational pattern for families of related products that must stay consistent. The client asks one for several products — button, dialog, menu — and never mixes Dark with Light.
Example: a settings screen in dark mode needs a dark button, dark dialog, and dark menu. If each widget has its own factory method, someone can place DarkButton next to LightDialog and the screen looks inconsistent. One kit per theme prevents that mix.
One product, or a family that must stay consistent?
Factory Method
1 product · which Vehicle?
Callers ask one factory for one interface. A new type is a new class plus one map entry. See Factory Method.
Abstract Factory
N products · which matching kit?
Callers ask a kit for several products. Swap the kit and the whole set changes together. Mixing families is the bug.
Two axes
Product types × families
The GoF picture is a grid. along one axis. Families along the other. The client depends on UiKit, Button, and Dialog — three stable types — and the concrete families live behind the kit.
| Kit | Button | Dialog |
|---|---|---|
| DarkUiKit | DarkButton | DarkDialog |
| LightUiKit | LightButton | LightDialog |
Client holds a UiKit. It never news DarkButton. Mixing DarkButton + LightDialog is the failure this pattern exists to prevent.
The kit — products that must match
interface Button { void paint(); }
interface Dialog { void paint(); }
interface UiKit {
Button button();
Dialog dialog();
}
class DarkUiKit implements UiKit {
public Button button() { return new DarkButton(); }
public Dialog dialog() { return new DarkDialog(); }
}
class LightUiKit implements UiKit {
public Button button() { return new LightButton(); }
public Dialog dialog() { return new LightDialog(); }
}
class SettingsScreen {
private final Button ok;
private final Dialog confirm;
SettingsScreen(UiKit kit) {
this.ok = kit.button();
this.confirm = kit.dialog();
}
}Not Abstract Factory — that is still Factory Method
One product. No family. Do not wrap this in a “kit” to sound senior.
// One product. No family. Do not wrap this in a kit.
interface VehicleFactory {
Vehicle from(String plate, String type);
}When a parking-lot round actually needs this
You rarely need Abstract Factory in a short interview. Vehicle creation is Factory Method. Allocation and pricing are Strategy. Reach for a kit when the interviewer forces a theme or vendor.
Report parts must match
PDF vs HTML: header, body, footer from the same renderer. Mixing a PDF header with an HTML footer is the inconsistent-theme bug.
Vendor payment kit
Stripe vs PayPal each give Charge + Refund + Payout. The checkout holds a PaymentKit, not three unrelated factories.
Mobile vs desktop widgets
A form built from one UiKit stays consistent. If you only create one widget, say so and use Factory Method.
Builder can sit next to the kit
Factory chooses the family of steps; Builder runs the steps. A ReportFactory can return a PdfReportBuilder or an HtmlReportBuilder. That is Abstract Factory plus Builder, not a reason to skip the consistency question.
Calling a single-product factory Abstract Factory
VehicleFactory.from(type) is Factory Method (or Simple Factory). Abstract Factory appears only when the client asks for several related products from one kit and must not mix families.
A kit whose products do not need to match
If a Car can pair with any Receipt printer, they are not a family. Two Factory Methods — or a factory plus a Strategy — are simpler. Abstract Factory is for consistency constraints, not for collecting new into one class.
What the client is allowed to know
SettingsScreen knows UiKit, Button, and Dialog. It does not know DarkUiKit unless the composition root injects that kit. Tests inject a FakeUiKit that returns no-op widgets. That is the same seam as dependency injection.
A registry can choose which kit to inject from a theme name. The registry picks the family. The kit creates the products. Do not put both jobs in SettingsScreen.
A payment kit, not three factories
Stripe and PayPal each expose charge, refund, and payout. If checkout news a StripeCharge next to a PayPalRefund, settlement looks inconsistent — the same bug as DarkButton plus LightDialog. One PaymentKit per vendor.
interface Charge { PaymentResult capture(Money amount, String orderId); }
interface Refund { PaymentResult reverse(String chargeId, Money amount); }
interface PaymentKit {
Charge charge();
Refund refund();
}
class StripeKit implements PaymentKit {
public Charge charge() { return new StripeChargeAdapter(stripe); }
public Refund refund() { return new StripeRefundAdapter(stripe); }
}How to explain this in an interview
“I hear two product types that must match. I will introduce a kit so the screen never mixes families.” Then draw the grid. Then write UiKit. Then stop. Do not also add a factory method for every widget unless the interviewer asks which class inside the family varies independently.
Explain it this way
Client depends on three stable types. Concrete families live behind the kit. Tests inject a fake kit.
Avoid saying this
“I will use Abstract Factory for vehicles.” One product is Factory Method. The name is not a promotion.