skip to content

What is the Abstract Factory pattern, and how does the JDK's DocumentBuilderFactory illustrate it?

level: juniorimportance: should knowfreq 55%

answer

  1. Factory of factories: creates a family of related products
  2. Client depends only on abstract factory + abstract products
  3. DocumentBuilderFactory.newInstance() then newDocumentBuilder()
  4. JAXP lookup picks the concrete provider at runtime
  5. Add variant = cheap; add product type = change every factory

basics

~20 s

Abstract Factory is a creational pattern: an object whose job is to create a family of related objects without you naming their concrete classes. DocumentBuilderFactory.newInstance() gives you a factory that builds matching XML parser objects.

solid answer

~40 s

Abstract Factory is a creational design pattern that provides an interface for creating a family of related objects without specifying their concrete classes. Client code asks a factory for products and receives concrete implementations chosen by the factory, so swapping the whole family means swapping one factory. In the JDK, DocumentBuilderFactory is the classic example: you call DocumentBuilderFactory.newInstance(), then newDocumentBuilder(), and the factory hands back a DocumentBuilder whose concrete type (the actual parser implementation) you never reference. The factory implementation is selected at runtime via the JAXP lookup mechanism (system property, jaxp.properties, service provider, or the platform default), so you can replace the parser library without touching client code. SAXParserFactory and XPathFactory follow the same shape. The benefit is decoupling: your code depends only on the abstract factory and abstract product types.

go deeper

for a junior

Can state that Abstract Factory creates related objects without naming concrete classes, and recognize DocumentBuilderFactory.newInstance() / newDocumentBuilder() as the JDK example.

for a middle

Explains the abstract-factory/abstract-product/client structure and that the JDK selects the concrete provider via JAXP lookup, keeping client code decoupled.

for a senior

Articulates the 'family of consistent products' invariant, contrasts it cleanly with Factory Method, and can describe the full JAXP lookup order and how to override the provider.

for a principal

Discusses when the indirection pays off vs. plain construction or DI, the cost of adding a new product type to the family, and how this pattern interacts with the service-provider mechanism and pluggability across module boundaries.

## The problem it solves Imagine code that needs to create objects, but you want to keep that code from being welded to specific concrete classes. If you write `new ApacheXercesDocumentBuilder()`, your code now knows the exact parser library and cannot be reconfigured without editing and recompiling. The **Abstract Factory** pattern removes that coupling. ### Definitions (from first principles) - A **creational pattern** is a design pattern concerned with *how objects are created* (as opposed to how they are structured or how they behave). - A **concrete class** is an actual, instantiable implementation (e.g. a specific parser). An **abstract type** (an interface or abstract class) names a capability without committing to an implementation. - A **product** is an object the factory creates. A **family of products** is a set of products that are meant to be used together and come from the same variant/provider. - The **Abstract Factory** is an object (often an interface or abstract class) that declares methods for creating each product in the family. A **concrete factory** is a specific implementation of that abstract factory that produces a matching set of concrete products. ### The shape of the pattern 1. Define abstract product types (interfaces/abstract classes). 2. Define an abstract factory with one creation method per product type. 3. Each concrete factory implements those methods to return one consistent family of concrete products. 4. **Client code holds a reference only to the abstract factory and abstract products** — it never writes `new` on a concrete product. Which concrete factory it gets is decided elsewhere (configuration, runtime lookup, dependency injection). ### The JDK example: `DocumentBuilderFactory` The Java API for XML Processing (JAXP) is built on Abstract Factory. To parse an XML document into a DOM tree you write: ```java DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(inputStream); ``` - `DocumentBuilderFactory` is the **abstract factory** (an abstract class). - `DocumentBuilder` (and the `Document`/parser objects it yields) are the **abstract products**. - `DocumentBuilderFactory.newInstance()` performs the **JAXP lookup**: it picks a concrete factory implementation by checking, in order, the `javax.xml.parsers.DocumentBuilderFactory` system property, a `jaxp.properties` file, the `ServiceLoader`/META-INF services mechanism, and finally the JDK's built-in default. The returned object is a concrete subclass you never name. - `factory.newDocumentBuilder()` then produces a concrete `DocumentBuilder` from that same provider — a **consistent family**: the builder, its parser, and the DOM nodes all come from one implementation. Because client code touches only `DocumentBuilderFactory` and `DocumentBuilder`, you can drop in a different XML library (or switch the system property) and the client is unchanged. `SAXParserFactory`, `XPathFactory`, and `TransformerFactory` are the same pattern in JAXP; `XMLInputFactory` (StAX) too. ### Why "family"? The defining trait of Abstract Factory (vs. plain Factory Method) is that one factory creates **multiple related products that must be consistent with each other**. A SAX provider must produce a parser and reader from the *same* implementation; you must not mix one library's reader with another's handler internals. The factory guarantees that consistency. ### Trade-offs - **Pro:** strong decoupling from concrete classes; swapping the whole family is a one-line/config change. - **Pro:** consistency — products from one factory are guaranteed compatible. - **Con:** adding a *new kind of product* to the family means changing the abstract factory and every concrete factory (the interface grows). Adding a new *variant* (new concrete factory) is cheap; adding a new *product type* is expensive. - **Con:** more indirection and classes than calling a constructor directly.

  • What does DocumentBuilderFactory.newInstance() actually do under the hood?
    It runs the JAXP provider-lookup sequence: it checks the javax.xml.parsers.DocumentBuilderFactory system property, then a jaxp.properties file in the JDK, then the ServiceLoader (META-INF/services) mechanism, then falls back to the JDK's built-in default factory. The first one found wins, and an instance of that concrete factory class is returned.
  • Name two other JAXP factories that follow the same pattern.
    SAXParserFactory (creates SAXParser/XMLReader objects), XPathFactory (creates XPath objects), TransformerFactory (XSLT transformers), and XMLInputFactory (StAX readers) are all Abstract Factory in JAXP.

saying these in an interview costs you the question

  • Saying Abstract Factory creates a single object — it creates a *family* of related products (that's what separates it from Factory Method).
  • Claiming you call `new` on the concrete parser — the whole point is the client never names the concrete class.
  • Confusing DocumentBuilderFactory (the factory) with DocumentBuilder (a product); the factory creates the builder.
  • Saying the provider is hardcoded — it's selected at runtime by JAXP lookup.

context