September 30, 2025
A comprehensive quick reference for code refactoring techniques and design patterns
refactoring design patternsWord Count: 4541
Attribution & Sources
This reference guide synthesizes industry-standard concepts from foundational works:
- Design Patterns: Based on “Design Patterns: Elements of Reusable Object-Oriented Software” (1994) by Gamma, Helm, Johnson, and Vlissides (Gang of Four)
- Refactoring Techniques: Based on “Refactoring: Improving the Design of Existing Code” by Martin Fowler (1999, 2nd ed. 2018)
- Code Smells: Term coined by Kent Beck, popularized by Martin Fowler
This guide provides our own organization, decision frameworks, and practical mappings for quick reference.
How to Use This Guide
For Quick Lookup:
- Jump to the relevant section using the table of contents
- Scan tables for symptoms or names you recognize
- Check “When to Apply” and “Complexity” columns for decision-making
For AI Agents:
- All entries follow consistent table structure
- Each technique includes: Name, Problem, Solution, When to Apply, Related Items
- Severity/Complexity ratings use standardized scales (Low/Medium/High)
Reading Guide:
- Severity/Impact: How much this problem hurts (Low/Medium/High/Critical)
- Complexity: How hard to implement the fix (Low/Medium/High)
- Risk: Chance of introducing bugs (Low/Medium/High)
Part I: Code Smells
Bloaters
Code, methods and classes that have grown so large they’re hard to work with.
| Smell | You See This | Severity | Why It’s Bad | Primary Techniques | Related Patterns |
|---|---|---|---|---|---|
| Long Method | Method > 50 lines, hard to understand what it does | High | Hides logic, hard to test, difficult to change | Extract Method, Replace Temp with Query, Replace Method with Method Object | Template Method, Strategy |
| Large Class | Class > 500 lines, doing too many things | High | Hard to maintain, violates SRP, difficult to test | Extract Class, Extract Subclass, Extract Interface | Facade, Composite |
| Primitive Obsession | Using primitives instead of small objects for simple tasks | Medium | Code duplication, unclear semantics, no type safety | Replace Data Value with Object, Replace Type Code with Class, Replace Array with Object | Value Object |
| Long Parameter List | Method has > 3-4 parameters | Medium | Hard to call, understand, or remember order | Replace Parameter with Method Call, Preserve Whole Object, Introduce Parameter Object | Builder, Parameter Object |
| Data Clumps | Same group of variables appear together repeatedly | Medium | Code duplication, unclear relationships | Extract Class, Introduce Parameter Object, Preserve Whole Object | Value Object |
Object-Orientation Abusers
Incomplete or incorrect application of object-oriented principles.
| Smell | You See This | Severity | Why It’s Bad | Primary Techniques | Related Patterns |
|---|---|---|---|---|---|
| Switch Statements | Type code with switch/case or long if-else chains on type | High | Violates Open/Closed, scattered logic, duplication | Replace Type Code with Subclasses, Replace Conditional with Polymorphism | Strategy, State, Factory Method |
| Temporary Field | Field only used in certain circumstances, null/empty otherwise | Medium | Confusing object state, unclear invariants | Extract Class, Replace Method with Method Object | Null Object, Special Case |
| Refused Bequest | Subclass doesn’t use inherited methods/fields | Medium | Misleading inheritance, violates LSP | Replace Inheritance with Delegation, Push Down Method/Field | Composition over Inheritance |
| Alternative Classes with Different Interfaces | Classes do similar things but have different method signatures | Medium | Code duplication, hard to swap implementations | Rename Method, Move Method, Extract Superclass | Adapter, Strategy |
Change Preventers
When you need to change one thing, you must change many other places too.
| Smell | You See This | Severity | Why It’s Bad | Primary Techniques | Related Patterns |
|---|---|---|---|---|---|
| Divergent Change | One class changes for many different reasons | High | Violates SRP, tangled responsibilities | Extract Class, Extract Superclass, Extract Subclass | Single Responsibility Principle |
| Shotgun Surgery | One change requires many small changes across many classes | Critical | Error-prone, time-consuming, high coupling | Move Method, Move Field, Inline Class | Facade, Mediator |
| Parallel Inheritance Hierarchies | When you add subclass to A, you must add to B too | Medium | Maintenance burden, duplication of structure | Move Method, Move Field, Collapse Hierarchy | Composition over Inheritance |
Dispensables
Pointless code whose absence would make the code cleaner.
| Smell | You See This | Severity | Why It’s Bad | Primary Techniques | Related Patterns |
|---|---|---|---|---|---|
| Comments | Excessive comments explaining what code does | Low | Often masks bad code, can become outdated | Extract Method, Rename Method, Introduce Assertion | Self-Documenting Code |
| Duplicate Code | Same or similar code appears in multiple places | High | Maintenance nightmare, bug multiplication | Extract Method, Extract Class, Pull Up Method, Form Template Method | Template Method, Strategy |
| Lazy Class | Class that doesn’t do enough to justify its existence | Low | Unnecessary abstraction, added complexity | Inline Class, Collapse Hierarchy | YAGNI Principle |
| Data Class | Class with only fields and getters/setters, no behavior | Medium | Anemic domain model, scattered logic | Move Method, Encapsulate Field, Encapsulate Collection | Rich Domain Model |
| Dead Code | Unused variables, methods, classes, or parameters | Low | Confusing, adds noise, maintenance burden | Delete it | Code Cleanup |
| Speculative Generality | Code built for future needs that don’t exist yet | Medium | Over-engineering, unnecessary complexity | Inline Class, Collapse Hierarchy, Remove Parameter | YAGNI Principle |
Couplers
Excessive coupling between classes.
| Smell | You See This | Severity | Why It’s Bad | Primary Techniques | Related Patterns |
|---|---|---|---|---|---|
| Feature Envy | Method uses more features of another class than its own | Medium | Wrong responsibility placement | Move Method, Extract Method | Law of Demeter |
| Inappropriate Intimacy | Classes know too much about each other’s internals | High | Tight coupling, hard to change independently | Move Method, Move Field, Change Bidirectional to Unidirectional, Hide Delegate | Mediator, Facade |
| Message Chains | Code like a.getB().getC().getD() |
High | Violates Law of Demeter, brittle to changes | Hide Delegate, Extract Method | Facade |
| Middle Man | Class exists only to delegate to another class | Low | Unnecessary indirection | Remove Middle Man, Inline Method | Direct Communication |
Other Smells
| Smell | You See This | Severity | Why It’s Bad | Primary Techniques | Related Patterns |
|---|---|---|---|---|---|
| Incomplete Library Class | Library doesn’t have method you need, can’t modify it | Low | Forced workarounds, scattered utility code | Introduce Foreign Method, Introduce Local Extension | Extension Methods, Adapter |
Part II: Refactoring Techniques
Composing Methods
Streamline methods, remove duplication, improve clarity.
| Technique | Problem | Solution | When to Apply | Complexity | Risk |
|---|---|---|---|---|---|
| Extract Method | Code fragment can be grouped together | Move code to separate method with descriptive name | Method > 10 lines, duplicated code, or needs comment to explain | Low | Low |
| Inline Method | Method body is more obvious than method name | Replace calls with method body, delete method | Over-abstraction, method does trivial work | Low | Low |
| Extract Variable | Hard to understand expression | Place result in variable with self-explanatory name | Complex expressions, repeated calculations | Low | Low |
| Inline Temp | Temp variable assigned simple expression, nothing more | Replace variable references with expression | Temp gets in way of other refactorings | Low | Low |
| Replace Temp with Query | Temp stores expression result for later use | Extract expression to method, replace temp with method calls | Temp used multiple times, needed by other methods | Medium | Low |
| Split Temporary Variable | Temp variable assigned different values at different times | Use different variables for different values | Loop variables excluded; temp reused for different purposes | Low | Low |
| Remove Assignments to Parameters | Value assigned to parameter inside method | Use local variable instead of parameter | Improves clarity, avoids confusion | Low | Low |
| Replace Method with Method Object | Long method with intertwined local variables | Transform into class where locals become fields | Extract Method blocked by local variable complexity | High | Medium |
| Substitute Algorithm | Want to replace algorithm with clearer one | Replace method body with new algorithm | Found clearer or more standard way | Medium | Medium |
Moving Features Between Objects
Safely move functionality between classes, create new classes.
| Technique | Problem | Solution | When to Apply | Complexity | Risk |
|---|---|---|---|---|---|
| Move Method | Method used more in another class than its own | Create method in other class, turn old into delegator or remove | Feature Envy smell detected | Medium | Low |
| Move Field | Field used more in another class than its own | Create field in other class, redirect all users | Feature Envy for data | Medium | Low |
| Extract Class | Class does work of two classes | Create new class, move relevant fields and methods | Large Class smell, or two clear responsibilities | Medium | Medium |
| Inline Class | Class does almost nothing | Move all features to another class, delete class | Lazy Class smell, class lost responsibility | Medium | Low |
| Hide Delegate | Client gets object B from object A, then calls B’s method | Create method in A that delegates to B | Message Chains smell, Law of Demeter violation | Low | Low |
| Remove Middle Man | Class has too many delegating methods | Force client to call end methods directly | Too many Middle Man methods | Low | Low |
| Introduce Foreign Method | Need method in utility class you can’t modify | Add method to client class with utility object as parameter | One or two methods needed | Low | Low |
| Introduce Local Extension | Utility class needs multiple methods you can’t add | Create new class as child or wrapper of utility class | Multiple methods needed, Foreign Method too messy | High | Medium |
Organizing Data
Improve data handling, replace primitives with rich classes.
| Technique | Problem | Solution | When to Apply | Complexity | Risk |
|---|---|---|---|---|---|
| Self Encapsulate Field | Direct access to private fields inside class | Create getter/setter, use only them for access | Need to control field access, prepare for subclassing | Low | Low |
| Replace Data Value with Object | Data field has behavior and associated data | Create new class for field and behavior | Primitive Obsession smell | Medium | Low |
| Change Value to Reference | Many identical instances need to be one object | Convert to single reference object | Need single source of truth | High | High |
| Change Reference to Value | Reference object too small and infrequently changed | Turn into value object (immutable) | Object too simple for reference management | Medium | Medium |
| Replace Array with Object | Array contains various types of data | Replace with object having separate fields | Array indices have meaning, not just sequential data | Low | Low |
| Duplicate Observed Data | Domain data stored in GUI-responsible classes | Separate data into domain classes, sync with GUI | Domain logic mixed with UI | High | High |
| Change Unidirectional Association to Bidirectional | Two classes need each other’s features, association only one way | Add missing association | Classes need to traverse both directions | Medium | Medium |
| Change Bidirectional Association to Unidirectional | Bidirectional association but one class doesn’t use it | Remove unused association | Reduce coupling, simplify | Medium | Medium |
| Replace Magic Number with Symbolic Constant | Number with specific meaning used directly | Create constant with human-readable name | Magic numbers in code | Low | Low |
| Encapsulate Field | Public field exists | Make private, create access methods | Exposed implementation details | Low | Low |
| Encapsulate Collection | Getter returns collection, setter exists | Make getter return read-only, create add/delete methods | Collection exposed directly | Medium | Medium |
| Replace Type Code with Class | Type code doesn’t affect behavior | Create class, use objects instead of codes | Type safety needed, codes are just labels | Medium | Low |
| Replace Type Code with Subclasses | Type code directly affects behavior in conditionals | Create subclasses for each code, extract behavior | Switch Statements smell on type | High | High |
| Replace Type Code with State/Strategy | Type code affects behavior but can’t use subclasses | Replace with state object | Type code changes at runtime | High | High |
| Replace Subclass with Fields | Subclasses differ only in constant-returning methods | Replace methods with fields in parent, delete subclasses | Subclasses too simple | Medium | Low |
Simplifying Conditional Expressions
Make conditional logic clearer and simpler.
| Technique | Problem | Solution | When to Apply | Complexity | Risk |
|---|---|---|---|---|---|
| Decompose Conditional | Complex conditional (if-then-else or switch) | Extract condition, then, and else into separate methods | Complex conditional hard to understand | Low | Low |
| Consolidate Conditional Expression | Multiple conditionals lead to same result | Consolidate into single expression | Multiple checks can be combined | Low | Low |
| Consolidate Duplicate Conditional Fragments | Identical code in all branches of conditional | Move code outside conditional | Code duplication in branches | Low | Low |
| Remove Control Flag | Variable acts as control flag for boolean expression | Use break, continue, or return instead | Control flag makes logic unclear | Low | Low |
| Replace Nested Conditional with Guard Clauses | Nested conditionals obscure normal execution path | Place special cases first with early returns | Deep nesting, hard to see normal flow | Low | Low |
| Replace Conditional with Polymorphism | Conditional performs different actions by object type | Create subclasses, extract behavior to them | Switch Statements smell, type-based conditionals | High | High |
| Introduce Null Object | Repeated checks for null | Create null object class with default behavior | Many null checks scattered | Medium | Medium |
| Introduce Assertion | Code assumes something about program state | Make assumption explicit with assertion | Implicit assumptions not documented | Low | Low |
Simplifying Method Calls
Make method calls simpler and interfaces clearer.
| Technique | Problem | Solution | When to Apply | Complexity | Risk |
|---|---|---|---|---|---|
| Rename Method | Method name doesn’t explain what it does | Rename it | Unclear intent, misleading name | Low | Low |
| Add Parameter | Method doesn’t have enough data to perform action | Create new parameter for necessary data | Missing information | Low | Low |
| Remove Parameter | Parameter not used in method body | Remove unused parameter | Dead parameter | Low | Low |
| Separate Query from Modifier | Method returns value AND changes object state | Split into two methods: query and modifier | Command-Query Separation violation | Medium | Medium |
| Parameterize Method | Methods do similar things, differ only in internal values | Combine using parameter for special value | Code duplication across similar methods | Medium | Low |
| Replace Parameter with Explicit Methods | Method run with parameter controlling behavior | Create separate method for each parameter value | Parameter values are discrete, limited set | Medium | Low |
| Preserve Whole Object | Getting values from object to pass as parameters | Pass whole object instead | Many parameters from same object | Low | Low |
| Replace Parameter with Method Call | Call method to get value, pass as parameter to another | Have method call the first method directly | Can get value directly in method | Low | Low |
| Introduce Parameter Object | Certain parameters naturally go together | Replace with object containing those parameters | Long Parameter List of related values | Medium | Medium |
| Remove Setting Method | Field should be set only at creation | Remove setter, set only in constructor | Immutable field | Low | Low |
| Hide Method | Method not used by other classes | Make private | Reduce public interface | Low | Low |
| Replace Constructor with Factory Method | Complex object creation logic in constructor | Replace with factory method | Complex instantiation, need type flexibility | Medium | Medium |
| Replace Error Code with Exception | Method returns special code for error | Throw exception instead | Error handling mixed with normal logic | Medium | Medium |
| Replace Exception with Test | Caller can check condition before calling | Replace exception with conditional test | Predictable, avoidable condition | Low | Low |
Dealing with Generalization
Move functionality along inheritance hierarchy, manage abstraction.
| Technique | Problem | Solution | When to Apply | Complexity | Risk |
|---|---|---|---|---|---|
| Pull Up Field | Two subclasses have same field | Move field to superclass | Duplicate fields in subclasses | Low | Low |
| Pull Up Method | Subclasses have identical methods | Move method to superclass | Duplicate behavior in subclasses | Low | Low |
| Pull Up Constructor Body | Subclass constructors have mostly same body | Move common parts to superclass constructor | Duplicate initialization | Medium | Low |
| Push Down Method | Behavior only relevant for some subclasses | Move to those subclasses | Not all subclasses need method | Low | Low |
| Push Down Field | Field only used by some subclasses | Move to those subclasses | Not all subclasses need field | Low | Low |
| Extract Subclass | Class has features used only in some instances | Create subclass for those features | Partial usage of class features | Medium | Medium |
| Extract Superclass | Two classes have common features | Create shared superclass | Duplicate structure across classes | Medium | Medium |
| Extract Interface | Multiple clients use same subset of class interface | Extract that subset into interface | Partial interface usage | Low | Low |
| Collapse Hierarchy | Superclass and subclass not very different | Merge them together | Speculative Generality smell | Low | Low |
| Form Template Method | Subclasses do similar things in same order but differently | Move structure to superclass, override steps | Similar algorithms with variations | Medium | Medium |
| Replace Inheritance with Delegation | Subclass uses only part of superclass interface | Create field for superclass, delegate to it | Refused Bequest smell | Medium | High |
| Replace Delegation with Inheritance | Many simple delegations to all methods | Make delegating class a subclass | Complete interface delegation | Medium | High |
Part III: Design Patterns
Creational Patterns
Patterns for object creation that increase flexibility and reuse.
| Pattern | Intent | Problem It Solves | When to Use | Key Benefit | Complexity |
|---|---|---|---|---|---|
| Factory Method | Define interface for creating objects, let subclasses decide which class to instantiate | Need to create objects without specifying exact class | Framework needs to create objects of types known only to application | Flexibility in object creation, loose coupling | Medium |
| Abstract Factory | Create families of related objects without specifying concrete classes | Need to create families of related/dependent objects | System must work with multiple families of products | Consistency across product families | High |
| Builder | Construct complex objects step-by-step, same construction process can create different representations | Complex object creation with many configuration options | Algorithm for creating complex object should be independent of parts | Step-by-step construction, different representations | Medium |
| Prototype | Create new objects by copying existing ones | Creating objects is expensive or complex | Classes to instantiate specified at runtime | Performance via cloning, dynamic configuration | Medium |
| Singleton | Ensure class has only one instance, provide global access | Need exactly one instance of class, globally accessible | Shared resource with single point of access needed | Controlled access, reduced namespace pollution | Low |
Structural Patterns
Patterns for assembling objects and classes into larger structures.
| Pattern | Intent | Problem It Solves | When to Use | Key Benefit | Complexity |
|---|---|---|---|---|---|
| Adapter | Convert interface of class into another interface clients expect | Incompatible interfaces prevent classes from working together | Need to use existing class with incompatible interface | Interface compatibility, reuse existing code | Low |
| Bridge | Decouple abstraction from implementation so both can vary independently | Implementation changes require recompiling abstraction | Want to avoid permanent binding between abstraction and implementation | Independent variation, reduced dependencies | High |
| Composite | Compose objects into tree structures, treat individual objects and compositions uniformly | Need to represent part-whole hierarchies | Clients should treat individual and composite objects uniformly | Uniform treatment, simplified client code | Medium |
| Decorator | Attach additional responsibilities to object dynamically | Need flexible alternative to subclassing for extending functionality | Responsibilities can be added/withdrawn at runtime | Flexible extension, avoids class explosion | Medium |
| Facade | Provide unified interface to set of interfaces in subsystem | Complex subsystem is difficult to use | Want simpler interface to complex subsystem | Simplified interface, loose coupling to subsystem | Low |
| Flyweight | Use sharing to support large numbers of fine-grained objects efficiently | Application uses large number of similar objects | Objects can share intrinsic state | Reduced memory usage, performance improvement | High |
| Proxy | Provide surrogate/placeholder for another object to control access | Need to control access to object or add functionality | Remote object, expensive object, or access control needed | Controlled access, lazy initialization | Medium |
Behavioral Patterns
Patterns for algorithms and assignment of responsibilities between objects.
| Pattern | Intent | Problem It Solves | When to Use | Key Benefit | Complexity |
|---|---|---|---|---|---|
| Chain of Responsibility | Pass request along chain of handlers until one handles it | Avoid coupling sender to receiver | More than one object may handle request, handler not known in advance | Reduced coupling, flexible request handling | Medium |
| Command | Encapsulate request as object | Need to parameterize objects with operations, queue requests, or support undo | Callback functionality, queuing, logging, or undo needed | Request as first-class object, undo/redo support | Medium |
| Iterator | Access collection elements sequentially without exposing representation | Need uniform way to traverse different collections | Traverse collection without exposing internal structure | Uniform access, multiple simultaneous traversals | Low |
| Mediator | Define object that encapsulates how set of objects interact | Objects refer to each other directly, creating tight coupling | Set of objects communicate in complex but well-defined ways | Reduced coupling, centralized control | Medium |
| Memento | Capture and externalize object’s internal state for later restoration | Need to save/restore object state without violating encapsulation | Undo mechanism or state snapshots needed | State preservation, encapsulation maintained | Medium |
| Observer | Define one-to-many dependency so when one object changes, dependents notified | Object state changes should trigger actions in other objects | One object change should notify unknown number of others | Loose coupling, broadcast communication | Medium |
| State | Allow object to alter behavior when internal state changes | Object behavior depends on state, many conditionals on state | Behavior varies by state, state transitions explicit | Localized state behavior, easier state transitions | High |
| Strategy | Define family of algorithms, make them interchangeable | Many related classes differ only in behavior | Need different variants of algorithm | Algorithm independence, easier to add variants | Low |
| Template Method | Define skeleton of algorithm, let subclasses override steps | Parts of algorithm should vary, but structure stays same | Algorithm structure fixed, but steps customizable | Code reuse, controlled extension points | Low |
| Visitor | Define new operation without changing classes it operates on | Need to perform operations across object structure with unrelated operations | Object structure classes rarely change, but operations change often | Easy to add operations, separation of concerns | High |
Part IV: Quick Decision Guides
Code Smell to Refactoring Mapping
Quick reference for which refactoring techniques address which code smells.
| Code Smell | Primary Refactoring Techniques | Alternative Approaches |
|---|---|---|
| Long Method | Extract Method → Replace Temp with Query → Replace Method with Method Object | Decompose Conditional, Substitute Algorithm |
| Large Class | Extract Class → Extract Subclass → Extract Interface | Extract Superclass, Hide Delegate |
| Primitive Obsession | Replace Data Value with Object → Replace Type Code with Class → Replace Array with Object | Introduce Parameter Object |
| Long Parameter List | Replace Parameter with Method Call → Preserve Whole Object → Introduce Parameter Object | Extract Method to reduce need |
| Data Clumps | Extract Class → Introduce Parameter Object → Preserve Whole Object | Move Method/Field |
| Switch Statements | Replace Type Code with Subclasses → Replace Conditional with Polymorphism | Replace Type Code with State/Strategy |
| Temporary Field | Extract Class → Replace Method with Method Object | Introduce Null Object |
| Refused Bequest | Replace Inheritance with Delegation → Push Down Method → Push Down Field | Extract Subclass |
| Alternative Classes | Rename Method → Move Method → Extract Superclass | Extract Interface |
| Divergent Change | Extract Class → Extract Superclass → Extract Subclass | Move Method/Field |
| Shotgun Surgery | Move Method → Move Field → Inline Class | Extract Class, Hide Delegate |
| Parallel Inheritance | Move Method → Move Field → Collapse Hierarchy | Prefer composition |
| Comments | Extract Method → Rename Method → Introduce Assertion | Self-documenting code |
| Duplicate Code | Extract Method → Extract Class → Pull Up Method → Form Template Method | Extract Superclass |
| Lazy Class | Inline Class → Collapse Hierarchy | Remove entirely |
| Data Class | Move Method → Encapsulate Field → Encapsulate Collection | Replace Data Value with Object |
| Dead Code | Delete it | None - just remove |
| Speculative Generality | Inline Class → Collapse Hierarchy → Remove Parameter | Simplify to current needs |
| Feature Envy | Move Method → Extract Method | Move Field |
| Inappropriate Intimacy | Move Method → Move Field → Change Bidirectional to Unidirectional → Hide Delegate | Extract Class, Replace Inheritance with Delegation |
| Message Chains | Hide Delegate → Extract Method | Introduce Foreign Method |
| Middle Man | Remove Middle Man → Inline Method | Extract Class if doing real work |
| Incomplete Library | Introduce Foreign Method → Introduce Local Extension | Adapter pattern |
Pattern Selection Guide
Choose the right design pattern based on your specific problem.
Creating Objects
| Your Situation | Recommended Pattern | Why |
|---|---|---|
| Need to create different types of objects based on runtime info | Factory Method | Delegates object creation to subclasses |
| Need to create families of related objects | Abstract Factory | Ensures consistency across product families |
| Creating object requires many configuration steps | Builder | Step-by-step construction with fluent interface |
| Creating object is expensive, need copies | Prototype | Clone existing objects instead of creating new |
| Need exactly one instance globally accessible | Singleton | Controlled instantiation and global access |
Structuring Objects
| Your Situation | Recommended Pattern | Why |
|---|---|---|
| Incompatible interfaces need to work together | Adapter | Makes incompatible interfaces compatible |
| Need to vary abstraction and implementation independently | Bridge | Separates abstraction from implementation |
| Need to represent part-whole hierarchies | Composite | Tree structure with uniform treatment |
| Need to add responsibilities to objects dynamically | Decorator | Flexible alternative to subclassing |
| Need simpler interface to complex subsystem | Facade | Provides unified interface |
| Many similar objects consuming too much memory | Flyweight | Shares common state to reduce memory |
| Need to control access to another object | Proxy | Adds indirection for access control |
Coordinating Objects
| Your Situation | Recommended Pattern | Why |
|---|---|---|
| Multiple handlers for request, handler not known | Chain of Responsibility | Decouples sender from receiver |
| Need to encapsulate requests as objects | Command | Treats requests as first-class objects |
| Need to traverse collection uniformly | Iterator | Provides uniform access to elements |
| Objects need to communicate but stay decoupled | Mediator | Centralizes communication |
| Need to capture and restore object state | Memento | Preserves state without breaking encapsulation |
| One object change should notify others | Observer | One-to-many dependency |
| Behavior changes based on internal state | State | Encapsulates state-specific behavior |
| Need interchangeable algorithms | Strategy | Makes algorithms interchangeable |
| Algorithm structure fixed, steps vary | Template Method | Defines algorithm skeleton |
| Need to add operations without changing classes | Visitor | Separates operations from objects |
Refactoring to Pattern Transitions
Common progressions from refactoring techniques to design patterns.
| Starting Point | Refactoring Steps | Resulting Pattern | When to Stop Refactoring |
|---|---|---|---|
| Long method with conditional logic | Extract Method → Replace Conditional with Polymorphism | Strategy / State | Classes clearly encapsulate behavior variants |
| Duplicate code across classes | Extract Method → Pull Up Method → Form Template Method | Template Method | Common algorithm structure with varying steps |
| Complex object creation | Extract Method → Replace Constructor with Factory Method | Factory Method | Creation logic complex enough to delegate |
| Multiple conditionals on type | Replace Type Code with Subclasses → Replace Conditional with Polymorphism | Strategy / State | Type-specific behavior in separate classes |
| Building complex object | Extract Method for each building step | Builder | Construction requires many configuration steps |
| Direct dependencies on concrete classes | Extract Interface → Use interface type declarations | Dependency Injection + Strategy | Dependencies injected, easily swappable |
| Method used in one class more than its own | Move Method → Extract Interface | Strategy | Behavior extracted and interchangeable |
| Message Chains | Hide Delegate repeatedly | Facade | Simplified interface to subsystem |
| Data Class with external behavior | Move Method to data class | Rich Domain Model | Behavior co-located with data |
| Switch on type code | Replace Type Code with State/Strategy → Extract state classes | State | State-specific behavior encapsulated |
Pattern Comparison Matrix
When choosing between similar patterns.
| Pattern A | Pattern B | Choose A When | Choose B When |
|---|---|---|---|
| Factory Method | Abstract Factory | Creating single products | Creating families of related products |
| Factory Method | Builder | Simple object creation | Complex step-by-step construction needed |
| Prototype | Factory Method | Performance critical, cloning cheaper | Need class hierarchy for creation |
| Strategy | State | Behavior doesn’t change during lifetime | Behavior changes based on state transitions |
| Strategy | Template Method | Want runtime algorithm switching | Algorithm structure is fixed |
| Decorator | Proxy | Adding responsibilities dynamically | Controlling access or lazy loading |
| Composite | Decorator | Part-whole hierarchies, tree structures | Linear enhancement of single object |
| Adapter | Facade | Making single class compatible | Simplifying entire subsystem |
| Bridge | Adapter | Design time: want to vary both abstraction and implementation | Runtime: need interface compatibility |
| Observer | Mediator | One-to-many notifications | Complex many-to-many interactions |
| Command | Strategy | Need undo/redo, queuing, logging | Just need interchangeable algorithms |
| Visitor | Strategy | Operations change frequently, structure stable | Structure varies, operations stable |
Severity and Priority Quick Reference
Prioritize which code smells to address first.
| Severity Level | Code Smells | Priority Action |
|---|---|---|
| Critical | Shotgun Surgery | Address immediately - blocks all changes |
| High | Long Method, Large Class, Switch Statements, Inappropriate Intimacy, Message Chains, Divergent Change, Duplicate Code | Address in next refactoring session |
| Medium | Primitive Obsession, Long Parameter List, Data Clumps, Temporary Field, Refused Bequest, Alternative Classes, Parallel Inheritance, Data Class, Feature Envy, Speculative Generality | Address when working in area |
| Low | Comments, Lazy Class, Dead Code, Middle Man, Incomplete Library | Address during cleanup or when opportunity arises |
Conclusion
This reference guide provides a structured approach to improving code quality through refactoring and design patterns. Key takeaways:
- Code Smells First: Identify problems before applying solutions
- Refactor Incrementally: Small steps with tests after each change
- Patterns Emerge: Don’t force patterns - let refactoring lead you there
- Context Matters: No absolute rules - consider your specific situation
- Continuous Improvement: Refactoring is ongoing, not a one-time activity
Further Reading
- Refactoring by Martin Fowler (2nd Edition, 2018)
- Design Patterns by Gang of Four (Gamma, Helm, Johnson, Vlissides)
- Refactoring to Patterns by Joshua Kerievsky
- Clean Code by Robert C. Martin
Additional Resources
- Refactoring.Guru - Visual guides and examples
- SourceMaking - Pattern catalog with examples
- Refactoring Catalog - Martin Fowler’s reference