upgrade
upgrade

Programming Languages and Techniques II

Essential Refactoring Techniques

Study smarter with Fiveable

Get study guides, practice questions, and cheatsheets for all your subjects. Join 500,000+ students with a 96% pass rate.

Get Started

Why This Matters

Refactoring is the disciplined art of restructuring existing code without changing its external behavior—and it's a skill you'll be tested on repeatedly throughout your programming career. Understanding these techniques connects directly to core course concepts like object-oriented design principles, code maintainability, and software architecture. When you encounter questions about cohesion, coupling, encapsulation, and polymorphism, refactoring techniques are often the practical application being assessed.

Don't just memorize what each technique does—know when to apply it and which design principle it supports. Exam questions frequently present you with problematic code and ask you to identify the appropriate refactoring, or they'll test whether you understand the trade-offs between techniques. Master the underlying concepts, and you'll recognize the right tool for any code smell you encounter.


Decomposition Techniques

These techniques break down complex code into smaller, more focused units. The core principle: smaller pieces are easier to understand, test, and reuse.

Extract Method

  • Breaks large methods into smaller, focused ones—each method should do exactly one thing and do it well
  • Improves testability by isolating functionality into units that can be tested independently
  • Enables code reuse across your codebase without duplicating logic

Extract Class

  • Creates a new class when an existing class handles too many responsibilities—look for clusters of related fields and methods
  • Enforces the Single Responsibility Principle by ensuring each class has one reason to change
  • Reduces class complexity making the original class easier to understand and maintain

Extract Interface

  • Separates the contract (what) from implementation (how)—defines what a class promises to do without dictating how
  • Enables dependency injection and mocking which is critical for writing effective unit tests
  • Promotes loose coupling by allowing code to depend on abstractions rather than concrete classes

Compare: Extract Method vs. Extract Class—both decompose complexity, but Extract Method works within a class while Extract Class creates new classes. If an exam asks about reducing method length, think Extract Method; if it's about a class with too many responsibilities, think Extract Class.


Naming and Clarity Techniques

Clear code communicates intent. These techniques make code self-documenting by ensuring names and structure reveal purpose.

Rename

  • Replaces vague names with descriptive onesx becomes customerAge, doStuff() becomes calculateTotalPrice()
  • Reduces cognitive load by eliminating the need to trace through code to understand what something represents
  • Maintains consistency across the codebase, making patterns recognizable

Replace Temp with Query

  • Eliminates temporary variables by using method calls—instead of int total = getBase() + getTax(); use a getTotal() method
  • Makes intent explicit through meaningful method names rather than variable assignments
  • Reduces variable scope minimizing the chance of accidental modification or side effects

Compare: Rename vs. Replace Temp with Query—Rename improves existing names, while Replace Temp with Query eliminates variables entirely by encoding their purpose in method names. Both improve readability, but Replace Temp with Query also improves structure.


Structural Organization Techniques

These techniques improve how code is organized across classes. The goal: high cohesion within classes, low coupling between them.

Move Method

  • Relocates a method to the class that uses its data most—if a method references another class's fields constantly, it probably belongs there
  • Increases cohesion by grouping related behavior with related data
  • Reduces coupling by eliminating cross-class dependencies and feature envy

Introduce Parameter Object

  • Bundles related parameters into a single objectcreateOrder(String name, String address, String city, String zip) becomes createOrder(Address address)
  • Simplifies method signatures making them easier to read and call correctly
  • Creates reusable data structures that can be passed throughout the system

Encapsulate Field

  • Replaces public fields with private fields plus getter/setter methods—protects internal state from external manipulation
  • Enables validation logic to be added without changing how clients access the data
  • Supports the information hiding principle allowing implementation changes without breaking dependent code

Compare: Move Method vs. Encapsulate Field—Move Method improves organization between classes, while Encapsulate Field improves organization within a class. Both reduce inappropriate access to data, but at different architectural levels.


Simplification Techniques

These techniques reduce complexity by removing unnecessary indirection or conditional logic. Sometimes the best code is less code.

Inline Method

  • Replaces a method call with the method's body—the opposite of Extract Method, used when a method adds no value
  • Removes unnecessary abstraction when a method's name says exactly what its single line of code does
  • Useful as an intermediate step before applying other refactorings to overly fragmented code

Replace Conditional with Polymorphism

  • Eliminates switch statements and if-else chains by using inheritance and method overriding
  • Delegates behavior to subclasses so each class handles its own case—open/closed principle in action
  • Improves extensibility since adding new behavior means adding new classes, not modifying existing conditionals

Compare: Inline Method vs. Extract Method—these are inverse operations. Extract Method is for code that's too long; Inline Method is for abstractions that don't earn their keep. Knowing when to apply each shows mastery of refactoring judgment.


Quick Reference Table

ConceptBest Examples
Single Responsibility PrincipleExtract Class, Extract Method, Move Method
Improving ReadabilityRename, Replace Temp with Query, Introduce Parameter Object
Reducing CouplingExtract Interface, Move Method, Encapsulate Field
Increasing CohesionMove Method, Extract Class
Enabling TestabilityExtract Interface, Extract Method, Encapsulate Field
Polymorphism & OOPReplace Conditional with Polymorphism, Extract Interface
Simplifying CodeInline Method, Replace Temp with Query
Data ProtectionEncapsulate Field, Introduce Parameter Object

Self-Check Questions

  1. A method in class Order frequently accesses fields from class Customer. Which refactoring technique would best improve this code's cohesion, and why?

  2. Compare and contrast Extract Method and Extract Class. Under what circumstances would you choose one over the other?

  3. You encounter a 15-line method with a temporary variable that's assigned once and used twice. Which two refactoring techniques might apply, and in what order would you apply them?

  4. How does Replace Conditional with Polymorphism support the open/closed principle? Give a scenario where this refactoring would be appropriate.

  5. A public field balance in a BankAccount class is accessed directly throughout the codebase. Which refactoring would you apply, and what additional capability does this enable that direct field access doesn't support?