Question 2 · Section 2

What Pattern Categories Exist?

Patterns are divided into three main categories depending on what they help you do:

Language versions: English Russian Ukrainian

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 instance
  • Factory Method — creation via subclass method
  • Abstract Factory — creation of object families
  • Builder — step-by-step creation
  • Prototype — 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 interfaces
  • Decorator — adding responsibilities at runtime
  • Proxy — surrogate for access control
  • Facade — simplified interface to a subsystem
  • Composite — 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 algorithms
  • Observer — subscription to changes
  • Chain of Responsibility — chain of handlers
  • State — behavior depends on state
  • Template 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-Controller
  • Hexagonal Architecture — ports and adapters
  • CQRS — read/write separation

Cloud-Native Patterns:

  • Circuit Breaker — protection from cascading failures
  • Saga — distributed transactions
  • Retry — retry attempts
  • Bulkhead — 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

  1. Determine the category when choosing a pattern
  2. Creational → fight new in business code
  3. Structural → composition > inheritance
  4. Behavioral → polymorphism > switch
  5. Cloud-Native mandatory for microservices
  6. Check interconnections between patterns
  7. Think about JIT when choosing implementation
  8. 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