Refactoring & Code Quality

Composing Methods & Conditionals

A family of refactorings targets conditional logic specifically: flattening nested ifs with guard clauses, decomposing a tangled condition into named pieces, and — when a type-code switch keeps growing — replacing it with polymorphic dispatch.
  • Guard clauses: handle the exceptional/early-exit cases first and return immediately, so the main logic isn't nested inside an if
  • Decompose Conditional: extract the condition, the then-branch, and the else-branch each into a well-named method
  • Replace Conditional with Polymorphism: turn a type-code switch into one method per subtype, each overriding a common method
  • The "one level of indentation" heuristic — deeply nested conditionals are themselves a smell (Long Method's conditional cousin)
  • Polymorphism wins when the same switch is duplicated at several call sites and the set of types keeps growing; a single, stable, local if is often clearer left alone
Nested conditionals → guard clauses
// Before: the "normal" case is buried three levels deep.
double getPayAmount(Employee e) {
    double result;
    if (e.isSeparated()) {
        result = 0;
    } else {
        if (e.isRetired()) {
            result = pension(e);
        } else {
            result = normalPay(e);
        }
    }
    return result;
}

// After: guard clauses handle exceptions first; the main path is flat.
double getPayAmount(Employee e) {
    if (e.isSeparated()) return 0;
    if (e.isRetired())  return pension(e);
    return normalPay(e);
}
Type-code switch → polymorphic dispatch
// Before: repeated at every call site that needs a rate.
double rateFor(Employee e) {
    switch (e.getType()) {
        case ENGINEER: return 1.0;
        case MANAGER:  return 1.5;
        case DIRECTOR: return 2.0;
        default: throw new IllegalArgumentException();
    }
}

// After: each subtype knows its own rate; no switch anywhere.
abstract class Employee { abstract double rate(); }
class Engineer extends Employee { double rate() { return 1.0; } }
class Manager  extends Employee { double rate() { return 1.5; } }
class Director extends Employee { double rate() { return 2.0; } }
Conditional or polymorphism?
SignalPrefer
One call site, stable set of cases, unlikely to growPlain conditional — polymorphism would be needless indirection
Same switch duplicated at several call sitesPolymorphism — one dispatch point instead of N copies to keep in sync
New cases get added regularly (OCP pressure, see Solid Principles)Polymorphism — a new case is a new subclass, no existing code edited
Sources
  • Refactoring: Improving the Design of Existing Code (2nd ed.)Ch. 9, 10 — Simplifying Conditional Logic; Moving Features
  • Head First Design Patterns (2nd ed.)Ch. 1 — Strategy Pattern