Definition
The delegation pattern forwards method calls to a contained delegate object rather than inheriting behavior.
- Control: the wrapper exposes only the methods it wants. Inheritance exposes all parent public methods, even unwanted ones.
- Flexibility: the delegate can be swapped at runtime via constructor injection. Inheritance is fixed at compile time.
- Enhancement: the wrapper can add logic before and after the delegated call (logging, validation, caching).
- Decorator pattern: a specific form of delegation where the wrapper implements the same interface as the delegate.
- Spring example:
@Transactionalproxies use delegation: the proxy forwards the call to the real bean and adds transaction management around it.
Inheritance: SavingsAccount IS-A Account at National Bank of India and automatically gets all of Account's public methods, even unwanted ones like transferInternational(). Delegation: SavingsAccountService HAS-A AccountOperations delegate and forwards deposit() and withdraw() but hides transferInternational(). The service controls what is visible.
Understanding the Concepts
What is the delegation pattern?
Delegation is composition over inheritance applied as a concrete pattern.
How does delegation differ from inheritance?
// Inheritance: exposes everything from parent
public class Account {
public void deposit(java.math.BigDecimal amount) { /* ... */ }
public void withdraw(java.math.BigDecimal amount) { /* ... */ }
public void transferInternational(String country, java.math.BigDecimal amount) { /* ... */ }
}
public class SavingsAccount extends Account {
// Inherits ALL: deposit, withdraw, transferInternational
// transferInternational() is unwanted for savings but it is inherited and public.
}
// Delegation: forwards only what you choose
public class SavingsAccountService {
private final Account delegate;
public SavingsAccountService(Account delegate) { this.delegate = delegate; }
public void deposit(java.math.BigDecimal amount) {
if (amount.compareTo(new java.math.BigDecimal("10000000")) > 0) {
throw new IllegalArgumentException("Savings deposit limit: Rs.1 crore");
}
delegate.deposit(amount); // delegates the actual work
}
public void withdraw(java.math.BigDecimal amount) {
delegate.withdraw(amount); // delegates
}
// transferInternational: deliberately NOT forwarded.
// Caller cannot call savingsService.transferInternational().
}
What are the three benefits?
// Benefit 1: Control (expose only what makes sense)
// Inheritance: all parent methods visible. Cannot hide transferInternational.
// Delegation: forward deposit + withdraw. Hide everything else.
// Benefit 2: Enhancement (decorate before/after)
public void deposit(java.math.BigDecimal amount) {
log.info("Before deposit: {}", amount);
validate(amount);
delegate.deposit(amount); // delegate
notifyCustomer("Deposited Rs." + amount);
}
// Benefit 3: Swappability (change delegate at runtime)
public class FlexibleService {
private AccountOperations delegate;
public void setDelegate(AccountOperations newDelegate) {
this.delegate = newDelegate; // swap at runtime
}
}
// Production: PostgresAccountOps. Testing: MockAccountOps.
How does delegation compare to inheritance?
| Aspect | Inheritance | Delegation |
|--------|------------|------------|
| API exposure | All parent methods | Only forwarded methods |
| Flexibility | Fixed at compile time | Swappable at runtime |
| Enhancement | Override + super.method() (fragile) | Add logic around delegate call |
| Coupling | Tight (child depends on parent internals) | Loose (depends on interface) |
What patterns use delegation?
- Decorator: wrapper implements same interface as delegate, adds behavior.
- Adapter: wrapper translates between incompatible interfaces.
- Proxy: wrapper controls access to the delegate (Spring @Transactional).
What should a senior engineer know?
- In Spring, all @Transactional proxies use delegation: the proxy intercepts the call, starts a transaction, delegates to the real bean, and commits or rolls back.
- Kotlin has built-in delegation syntax:
class Stack.(private val list: MutableList ) : MutableList by list - Project Lombok's @Delegate annotation generates delegation boilerplate automatically.
Visual Overview
INHERITANCE
┌────────────────────────┐
│ Account │
│ deposit() │
│ withdraw() │
│ transferInternational() │ <- unwanted but inherited
└──────────┬─────────────┘
│ extends
┌──────────┴─────────────┐
│ SavingsAccount │
│ ALL methods visible │
└────────────────────────┘
DELEGATION
┌────────────────────────┐
│ SavingsAccountService │
│ deposit() -> delegate │ forwarded
│ withdraw() -> delegate │ forwarded
│ │
│ transferInternational() │ NOT forwarded (hidden)
│ ┌──────────────────┐ │
│ │ Account delegate │ │ private field
│ └──────────────────┘ │
└────────────────────────┘
Key Takeaway
The delegation pattern forwards method calls to a contained delegate object instead of inheriting behavior. The wrapper class holds a reference to the delegate and controls which methods are forwarded, unlike inheritance where all parent public methods are automatically exposed. Delegation provides three advantages: control (expose only deposit and withdraw, hide transferInternational), enhancement (add validation and logging around each delegated call), and flexibility (swap the delegate at runtime for testing or different implementations).
Delegation is composition over inheritance applied as a pattern. The Decorator pattern is a specific form where the wrapper implements the same interface as the delegate. In Spring, @Transactional proxies use delegation: the proxy forwards the call to the real bean, adding transaction management around the delegation.
Remember one sentence: delegation forwards selected calls to a contained object, giving control over what is exposed, flexibility to swap at runtime, and the ability to add logic around each call.
---