What Pattern Categories Exist?
Patterns are divided into three main categories depending on what they help you do:
Junior Level
Patterns are divided into three main categories depending on what they help you do:
1. Creational — hide WHAT is created, WHEN, and HOW. Code should not depend on concrete classes via new.
- Like
Builder— step-by-step creation of a complex object - Like
Singleton— guarantee of a single instance - Like
Factory— creating objects through a factory
2. Structural — help connect classes
- Like
Adapter— makes different interfaces compatible - Like
Decorator— adds functionality via wrapping - Like
Proxy— replaces an object with a surrogate
3. Behavioral — decide: who calls whom, when, and under what conditions.
- Like
Strategy— swapping algorithms - Like
Observer— event subscription - Like
Iterator— element iteration
Simple analogy: Building a house
- Creational — how to create bricks, windows, doors
- Structural — how to connect them together
- Behavioral — how people will use the house
When NOT to think in category terms
For simple CRUD applications, pattern categories are excessive. Use a pattern only when it solves a specific problem.
Middle Level
1. Creational Patterns
Focus: Encapsulating object creation
Why: Decoupling the system from concrete implementations
// Without Factory — tight coupling
User user = new User();
Order order = new Order();
// With Factory — flexibility
User user = userFactory.create();
Order order = orderFactory.create();
Key patterns:
Singleton— single instanceFactory Method— creation via subclass methodAbstract Factory— creation of object familiesBuilder— step-by-step creationPrototype— object copying
In Modern Java:
// Static factory methods in interfaces
List<String> list = List.of("a", "b", "c"); // Instead of new ArrayList()
Optional<String> opt = Optional.of(value); // Factory Method
2. Structural Patterns
Focus: Composing classes into larger structures
Why: Solving compatibility issues without inheritance
// Decorator — adding functionality
InputStream input = new BufferedInputStream(
new FileInputStream("file.txt")
);
// Adapter — interface compatibility
List<String> list = Collections.enumeration(arrayList);
Key patterns:
Adapter— combining incompatible interfacesDecorator— adding responsibilities at runtimeProxy— surrogate for access controlFacade— simplified interface to a subsystemComposite— tree structure
In Spring:
// Proxy — the basis of all Spring "magic"
@Transactional // Proxy around the bean
@Cacheable // Proxy with caching
@Async // Proxy for asynchrony
3. Behavioral Patterns
Focus: Algorithms and responsibility distribution
Why: Managing signal transmission dynamics
// Strategy — swapping algorithms
Comparator<String> byLength = (a, b) -> a.length() - b.length();
list.sort(byLength);
// Observer — event subscription
button.addActionListener(e -> System.out.println("Clicked!"));
Key patterns:
Strategy— family of algorithmsObserver— subscription to changesChain of Responsibility— chain of handlersState— behavior depends on stateTemplate Method— algorithm skeleton
4. Extended Classification
Concurrency Patterns:
// Read-Write Lock
ReadWriteLock rwLock = new ReentrantReadWriteLock();
// Producer-Consumer
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
ExecutorService executor = Executors.newFixedThreadPool(10);
Architectural Patterns:
MVC— Model-View-ControllerHexagonal Architecture— ports and adaptersCQRS— read/write separation
Cloud-Native Patterns:
Circuit Breaker— protection from cascading failuresSaga— distributed transactionsRetry— retry attemptsBulkhead— resource isolation
Senior Level
Architectural Meaning of Categories
Category = level of complexity management:
| Category | Problem Solved | Code Smell |
|---|---|---|
| Creational | Tight coupling on creation | Many new in business code |
| Structural | Complexity of relationships | Subclass explosion, incompatibility |
| Behavioral | Interaction logic | Huge switch/if-else |
Creational: Dependency Inversion in Practice
DIP (Dependency Inversion Principle) — depend on abstractions, not details. OCP (Open/Closed Principle) — open for extension, closed for modification.
If business code has many `new` → DIP violation
Solution:
1. Simple Factory (static method)
2. Factory Method (inheritance)
3. Abstract Factory (families)
4. DI Container (Spring)
Evolution:
// Level 1: Simple Factory
public static UserService create() { return new UserServiceImpl(); }
// Level 2: Factory Method
public abstract class Factory { abstract UserService create(); }
// Level 3: Abstract Factory
public interface AppFactory {
UserService createUser();
OrderService createOrder();
PaymentService createPayment();
}
// Level 4: DI Container
@Component
public class UserService { } // Spring will create it itself
Structural: Composition vs Inheritance
Decorator instead of inheritance:
// Inheritance → class explosion
class BufferedFileInputStream extends FileInputStream { }
class EncryptedFileInputStream extends FileInputStream { }
class BufferedEncryptedFileInputStream extends FileInputStream { }
// → 2^n classes for n functions!
// Decorator → composition
new BufferedInputStream(
new CipherInputStream(
new FileInputStream("file.txt")
)
)
// → n classes for n functions
Behavioral: Polymorphism instead of switch
// Procedural approach
switch (paymentType) {
case CREDIT_CARD: processCreditCard(); break;
case PAYPAL: processPayPal(); break;
case CRYPTO: processCrypto(); break;
}
// OOP approach (Strategy)
interface PaymentStrategy { void process(); }
class CreditCardPayment implements PaymentStrategy { ... }
class PayPalPayment implements PaymentStrategy { ... }
paymentStrategy.process(); // Polymorphism
Modern Java:
// Enum Map Strategy
Map<PaymentType, PaymentStrategy> strategies = Map.of(
CREDIT_CARD, this::processCreditCard,
PAYPAL, this::processPayPal,
CRYPTO, this::processCrypto
);
strategies.get(type).process();
Category Interconnections in Real Systems
Spring Context as a “Meta-Factory”:
ApplicationContext (Creational)
→ creates beans
→ wraps in Proxy (Structural)
→ which manages behavior (Behavioral)
Typical chain:
Abstract Factory (Creational)
→ returns Proxy (Structural)
→ which wraps business logic
→ managed via Strategy (Behavioral)
→ assembled via Builder (Creational)
→ with Chain of Responsibility (Behavioral) for validation
Performance Implications
JIT and polymorphism:
Monomorphic call (1 implementation)
→ JIT inlines code
→ 0 overhead
Bimorphic call (2 implementations)
→ JIT still optimizes
→ Minimal overhead
Megamorphic call (>2 implementations)
→ Indirect call via vtable
→ Measurable CPU drop
Hot-path optimization:
// Instead of interface → enum
public enum CompressionType {
GZIP { @Override public byte[] compress(byte[] data) { ... } },
LZ4 { @Override public byte[] compress(byte[] data) { ... } };
public abstract byte[] compress(byte[] data);
}
// → JIT better optimizes enum switch table
Cloud-Native Patterns Deep Dive
Circuit Breaker:
@CircuitBreaker(name = "backendA", fallbackMethod = "fallback")
public String getData() {
return restTemplate.getForObject("http://service-a", String.class);
}
Saga Pattern:
Order Service → create order
↓
Payment Service → deduct money
↓
Inventory Service → reserve product
↓ (if error)
Compensating Transactions → rollback everything
Production Experience
Real scenario: Categorization helped find root cause
- System: 200+ classes, hard to understand what’s where
- Analysis by category:
- Creational: 30 Factory classes (overengineering)
- Structural: 50 Decorator (needed)
- Behavioral: 80 Strategy (duplication)
- Solution:
- Replaced Factory with DI
- Consolidated Strategy → Map
- Result: -40% classes, +readability
Best Practices
- Determine the category when choosing a pattern
- Creational → fight
newin business code - Structural → composition > inheritance
- Behavioral → polymorphism > switch
- Cloud-Native mandatory for microservices
- Check interconnections between patterns
- Think about JIT when choosing implementation
- Modern Java simplifies many categories
Senior Summary
- Creational = fighting tight coupling on creation
- Structural = managing relationship complexity
- Behavioral = managing interaction logic
- Category = level of architectural complexity management
- Interconnection: patterns from different categories work together
- JIT: megamorphic calls affect performance
- Cloud-Native patterns critical for microservices
- Spring Context = mega-factory of all categories
Interview Cheat Sheet
Must know:
- Three main categories: Creational (object creation), Structural (class composition), Behavioral (interaction)
- Creational hides the creation process, Structural solves compatibility issues, Behavioral manages algorithms
- In Modern Java: Factory Method is replaced by Supplier
, Singleton — by DI container (Spring @Component) - Spring @Transactional, @Cacheable, @Async work through Proxy (Structural pattern)
- Cloud-Native patterns: Circuit Breaker, Saga, Retry, Bulkhead — mandatory for microservices
- Categories help identify root architectural problems and choose the right solution
- Evolution: Simple Factory → Factory Method → Abstract Factory → DI Container
Common follow-up questions:
- Which pattern replaces switch in business code? — Strategy (Behavioral), Map<Enum, Function>
- What is a megamorphic call? — Method call with >2 interface implementations, JIT cannot inline
- How does Spring manage bean creation? — ApplicationContext as a “mega-factory” of all pattern categories
- When are pattern categories excessive? — In simple CRUD applications and prototypes
Red flags (DO NOT say):
- “I don’t need categories, I write code without patterns” — ignorance of architectural foundations
- “All patterns are obsolete with Spring” — Spring itself uses patterns under the hood
- “Creational patterns are only needed in Java” — they apply to any OOP language
- “Structural patterns are only for GUI” — Adapter, Decorator, Proxy are everywhere in Spring
Related topics:
- [[01. What are design patterns]] — general introduction and pattern levels
- [[03. What is Singleton]] — Creational pattern
- [[12. Advantage of Decorator over inheritance]] — Structural pattern
- [[10. When to use Strategy]] — Behavioral pattern
- [[14. What Proxy types exist]] — Structural pattern in Spring