Extension Object
The Extension Object pattern adds new queryable interfaces to a class over time without modifying it, keeping the core lean and enabling third-party extension. Runtime capability queries add complexity.
The Extension Object pattern lets you anticipate that a class's responsibilities will grow and provides a way to add new interfaces and behavior to objects without modifying their core class. Instead of piling every possible capability onto one class, the core object exposes a way to ask for an extension by type and returns a separate object implementing that capability if it is supported. It solves the tension between keeping a class focused and allowing it to gain new, optional abilities over time — including from third parties.
How It Works
A Subject (the core class) provides a method such as getExtension(type) that returns an extension object for the requested interface, or null/absent if it is unsupported. Each Extension is an interface declaring a coherent set of operations; Concrete Extensions implement them, usually holding a back-reference to the subject so they can operate on its state. The subject maintains a registry mapping extension types to instances and may create or look them up on demand.
Clients that need an optional capability query for its extension, check whether it was returned, and use it. The subject's own interface stays small; capabilities accrete as separate, independently versioned extensions.
When to Use It
Use the Extension Object pattern when you foresee a class acquiring new, optional interfaces over time, when you want to avoid bloating a class with rarely used methods, and when you want third parties or plugins to attach new behavior without altering or subclassing the original. It is common in component models and IDE/plugin frameworks, where objects expose queryable capabilities (this idea underlies COM's QueryInterface and Eclipse's adapter mechanism).
It is overkill when the set of responsibilities is stable and known up front; a plain interface is simpler there.
Trade-offs
The pattern keeps the core class lean and focused while allowing open-ended, even third-party, extension, supporting the open/closed principle. Capabilities can evolve and version independently, and clients only depend on the extensions they actually use.
The costs are added complexity and indirection: clients must query for an extension and handle its absence, which is more cumbersome than calling a method directly and pushes capability checks to runtime rather than compile time. Discoverability suffers because available extensions are not visible on the core interface. Managing the extension registry and back-references adds bookkeeping, and over-applied the pattern fragments behavior across many small objects.
Related Patterns
Extension Object is related to Decorator and Adapter — all add capability to objects — but it specifically lets clients query for new interfaces at runtime rather than wrapping or converting. It complements Visitor, another way to add operations to a class hierarchy without modifying it, and underlies capability-query mechanisms in component frameworks.
Example
A document model has a small Document core. A spell-checker plugin needs spell-check operations, so it asks document.getExtension(SpellCheckable.class). If the document supports it, the call returns a SpellCheckExtension that operates on the document's text; if not, it returns null and the plugin disables the feature. New tools add their own extension types without the Document class ever changing, enabling an extensible plugin ecosystem.