01. Extract Method 02. Inline Method 03. Extract Class 04. Inline Class 05. Move Method 06. Move Field 07. Replace Temp with Query 08. Rename Variable / Method 09. Pull Up Field 10. Push Down Field 11. Pull Up Method 12. Push Down Method 13. Extract Interface 14. Replace Type Code with Subclasses 15. Decompose Conditional 16. Introduce Parameter Object 17. Replace Conditional with Polymorphism 18. Substitute Algorithm
01
Extract Method Problem: A method does too many things at once, mixing several concerns into one long block of code.
Solution: Move a cohesive chunk of the method into its own well-named method, then call that method from the original spot.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Book {
void printDetails() {
System.out.println(title);
System.out.println(author);
System.out.println(isbn);
System.out.println(price);
}
} AFTER REFACTORING
RefactoredStructure.java java
Copy class Book {
void printDetails() {
printIdentity();
printPrice();
}
void printIdentity() {
System.out.println(title);
System.out.println(author);
System.out.println(isbn);
}
void printPrice() {
System.out.println(price);
}
} MEMORY CUE: long method becomes a smaller method.
02
Inline Method Problem: A method's body is exactly as clear as its name, so calling it just adds an extra hop for no real benefit.
Solution: Remove the method and place its one line of logic directly where it was called.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy boolean moreThanFive() {
return score > 5;
}
int getRating() {
return moreThanFive() ? 2 : 1;
} AFTER REFACTORING
RefactoredStructure.java java
Copy int getRating() {
return score > 5 ? 2 : 1;
} MEMORY CUE: a small unnecessary method becomes code placed directly.
03
Extract Class Problem: A single class has grown to cover more than one responsibility, which usually points at a Single Responsibility Principle violation.
Solution: Move the related fields and methods for one responsibility into a new class of their own.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Customer {
String name;
String phoneNumber;
String areaCode;
} AFTER REFACTORING
RefactoredStructure.java java
Copy class Customer {
String name;
PhoneNumber phone;
}
class PhoneNumber {
String areaCode;
String phoneNumber;
} MEMORY CUE: one class doing too much splits into two.
04
Inline Class Problem: A class barely does anything on its own anymore and just adds an extra layer between the caller and the real work.
Solution: Move its remaining behavior into the class that uses it, then delete the now unnecessary class.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class ConsoleWriter {
void writeLine(String text) {
System.out.println(text);
}
}
class Report {
ConsoleWriter writer = new ConsoleWriter();
void print(String content) {
writer.writeLine(content);
}
} AFTER REFACTORING
RefactoredStructure.java java
Copy class Report {
void print(String content) {
System.out.println(content);
}
} MEMORY CUE: a useless small class merges into its caller.
05
Move Method Problem: A method in one class relies mostly on the data of a different class, calling that class's fields over and over.
Solution: Move the method to the class whose data it actually uses.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Order {
Cart cart;
double calculateTotal() {
double total = 0;
for (Item item : cart.items) {
total += item.price;
}
return total;
}
} AFTER REFACTORING
RefactoredStructure.java java
Copy class Cart {
List<Item> items;
double calculateTotal() {
double total = 0;
for (Item item : items) {
total += item.price;
}
return total;
}
}
class Order {
Cart cart;
double getTotal() {
return cart.calculateTotal();
}
} MEMORY CUE: behavior belongs with the data it uses most.
06
Move Field Problem: A field is read and updated by another class more than by the class that declares it.
Solution: Relocate the field to the class that actually owns that responsibility.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Order {
double discountRate;
}
class PricingEngine {
double apply(Order order, double amount) {
return amount - (amount * order.discountRate);
}
} AFTER REFACTORING
RefactoredStructure.java java
Copy class PricingEngine {
double discountRate;
double apply(double amount) {
return amount - (amount * discountRate);
}
} MEMORY CUE: data belongs with the class that uses it most.
07
Replace Temp with Query Problem: A temporary variable simply stores the result of an expression, adding a local variable for something that could just be computed on demand.
Solution: Replace the temporary variable with a method that calculates the value.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy double basePrice = quantity * itemPrice;
if (basePrice > 1000) {
applyDiscount();
} AFTER REFACTORING
RefactoredStructure.java java
Copy if (basePrice() > 1000) {
applyDiscount();
}
double basePrice() {
return quantity * itemPrice;
} MEMORY CUE: a temp variable becomes a method (a query).
08
Rename Variable / Method Problem: A name does not clearly explain its purpose, forcing readers to guess or dig through the code to understand it.
Solution: Give it a meaningful name that describes what it actually holds or does.
Code Transformation Both Before After
AFTER REFACTORING
RefactoredStructure.java java
MEMORY CUE: a good name means the code explains itself.
09
Pull Up Field Problem: Multiple subclasses independently declare the exact same field.
Solution: Move the shared field up into the common superclass, so it is declared once.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Dog extends Animal {
int age;
}
class Cat extends Animal {
int age;
} AFTER REFACTORING
RefactoredStructure.java java
Copy class Animal {
int age;
}
class Dog extends Animal {
}
class Cat extends Animal {
} MEMORY CUE: a common field moves up to the parent.
10
Push Down Field Problem: A field lives in the superclass, but only some subclasses actually need it.
Solution: Move the field down into just the subclasses that need it.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Animal {
int wings;
}
class Bird extends Animal {
}
class Dog extends Animal {
// does not need wings
} AFTER REFACTORING
RefactoredStructure.java java
Copy class Animal {
}
class Bird extends Animal {
int wings;
}
class Dog extends Animal {
} MEMORY CUE: a specific field moves down to the child.
11
Pull Up Method Problem: Subclasses each implement an identical method, duplicating the same logic more than once.
Solution: Move the common method up into the superclass so it exists in one place.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Dog extends Animal {
void eat() {
System.out.println("Eating");
}
}
class Cat extends Animal {
void eat() {
System.out.println("Eating");
}
} AFTER REFACTORING
RefactoredStructure.java java
Copy class Animal {
void eat() {
System.out.println("Eating");
}
}
class Dog extends Animal {
}
class Cat extends Animal {
} MEMORY CUE: a duplicate method moves up to the parent.
12
Push Down Method Problem: A method sits in the superclass, but only some subclasses can meaningfully perform it.
Solution: Move the method down into just the subclasses that need it.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Animal {
void fly() {
System.out.println("Flying");
}
}
class Bird extends Animal {
}
class Dog extends Animal {
// cannot fly
} AFTER REFACTORING
RefactoredStructure.java java
Copy class Animal {
}
class Bird extends Animal {
void fly() {
System.out.println("Flying");
}
}
class Dog extends Animal {
} MEMORY CUE: a specific method moves down to the child.
13
Extract Interface Problem: Several client classes only need a small, common subset of a class's methods, creating an unnecessarily tight dependency on the whole class.
Solution: Create an interface containing just those required methods, and have the class implement it.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Customer {
double calculateBill() {
return 100;
}
void updateAddress(String address) {
}
} AFTER REFACTORING
RefactoredStructure.java java
Copy interface Billable {
double calculateBill();
}
class Customer implements Billable {
public double calculateBill() {
return 100;
}
void updateAddress(String address) {
}
} MEMORY CUE: common behavior becomes an interface.
14
Replace Type Code with Subclasses Problem: A type code or switch statement decides how an object should behave, forcing every new case to edit the same method.
Solution: Create a subclass for each variant and let each one handle its own behavior.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Employee {
String type;
double bonus() {
if (type.equals("ENGINEER")) {
return 500;
} else if (type.equals("MANAGER")) {
return 1000;
}
return 0;
}
} AFTER REFACTORING
RefactoredStructure.java java
Copy abstract class Employee {
abstract double bonus();
}
class Engineer extends Employee {
double bonus() {
return 500;
}
}
class Manager extends Employee {
double bonus() {
return 1000;
}
} MEMORY CUE: type code becomes a subclass hierarchy.
15
Decompose Conditional Problem: A conditional statement mixes the condition and its logic together in one hard-to-read line.
Solution: Extract the condition and each branch's logic into clearly named methods.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy if (date.after(SUMMER) && date.before(WINTER)) {
charges = quantity * summerRate;
} else {
charges = quantity * winterRate;
} AFTER REFACTORING
RefactoredStructure.java java
Copy if (isSummer(date)) {
charges = summerCharges();
} else {
charges = winterCharges();
}
boolean isSummer(Date date) {
return date.after(SUMMER) && date.before(WINTER);
} MEMORY CUE: a complex if becomes small, named methods.
16
Introduce Parameter Object Problem: A method takes too many related parameters, making calls hard to read and easy to get wrong.
Solution: Group the related parameters into a single object and pass that instead.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy void bookRoom(Date start, Date end,
int guests, boolean vip) {
// booking logic
} AFTER REFACTORING
RefactoredStructure.java java
Copy void bookRoom(BookingRequest request) {
// booking logic
}
class BookingRequest {
Date start;
Date end;
int guests;
boolean vip;
} MEMORY CUE: many related parameters become one parameter object.
17
Replace Conditional with Polymorphism Problem: A switch or if statement checks an object's type to decide which behavior to run.
Solution: Give each type its own subclass with an overridden method, so the correct behavior runs through dynamic method dispatch instead of a type check.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy class Duck {
String type;
String quack() {
if (type.equals("MALLARD")) {
return "Quack!";
} else if (type.equals("RUBBER")) {
return "Squeak!";
}
return "...";
}
} AFTER REFACTORING
RefactoredStructure.java java
Copy abstract class Duck {
abstract String quack();
}
class MallardDuck extends Duck {
String quack() {
return "Quack!";
}
}
class RubberDuck extends Duck {
String quack() {
return "Squeak!";
}
} MEMORY CUE: a switch based on type becomes polymorphism. This connects directly to dynamic method dispatch.
18
Substitute Algorithm Problem: An existing algorithm works correctly, but a simpler or clearer one could produce the exact same result.
Solution: Replace the old algorithm with the cleaner one while keeping the same behavior.
Code Transformation Both Before After
BEFORE REFACTORING
LegacyStructure.java java
Copy boolean containsItem(List<String> list, String target) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals(target)) {
return true;
}
}
return false;
} AFTER REFACTORING
RefactoredStructure.java java
Copy boolean containsItem(List<String> list, String target) {
return list.contains(target);
} MEMORY CUE: same result, better algorithm.