Fundamentals 15 min read

Refactoring Techniques: Extract Function, Parameterize, Strategy Pattern, and More

This article presents a series of refactoring techniques—including extracting functions, parameterizing functions, applying the strategy pattern, extracting variables, splitting loops, and using guard clauses—illustrated with JavaScript code examples to improve readability, maintainability, and modularity of existing code bases.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Refactoring Techniques: Extract Function, Parameterize, Strategy Pattern, and More

Extract Function

What: Move a code fragment into its own function and name it after its purpose.

Where: When you need to spend time reading a block of code to understand its intent, extract it into a function so the name conveys its role.

How:

// ===================Before Refactoring==================
function printOwing(invoice) {
    let outstanding = 0;
    console.log("***********************");
    console.log("**** Customer Owes ****");
    console.log("***********************");
}

// ===================After Refactoring===================
function printOwing(invoice) {
    let outstanding = 0;
    printBanner();
}

function printBanner() {
    console.log("***********************");
    console.log("**** Customer Owes ****");
    console.log("***********************");
}

Function Parameterization

What: Pass different values as parameters to eliminate duplicate functions.

Where: When two functions have almost identical logic except for literal values, merge them into one function with parameters.

How:

// ===================Before Refactoring==================
clickFaultsItem(item){
    this.$u.route({url:'xxx',params:{id: item.id,type:'异常'}})
}
clickNormalItem(item){
    this.$u.route({url:'xxx',params:{id: item.id,type:'正常'}})
}

// ===================After Refactoring===================
clickItem(id, type){
    this.$u.route({url:'xxx',params:{id, type}})
}

Replace "Fat" Branches with Strategy Pattern

What: Use the strategy pattern to replace large if‑else or switch‑case blocks.

Where: When a function contains many conditional branches that perform similar operations.

How:

// ===================Before Refactoring==================
function getPrice(tag, originPrice) {
    if(tag === 'newUser') { return originPrice > 50.1 ? originPrice - 50 : originPrice; }
    if(tag === 'back')    { return originPrice > 200 ? originPrice - 50 : originPrice; }
    if(tag === 'activity'){ return originPrice > 300 ? originPrice - 100 : originPrice; }
}

// ===================After Refactoring===================
const priceHandler = {
    newUser(originPrice){ return originPrice > 50.1 ? originPrice - 50 : originPrice; },
    back(originPrice){    return originPrice > 200 ? originPrice - 50 : originPrice; },
    activity(originPrice){return originPrice > 300 ? originPrice - 100 : originPrice; }
};
function getPrice(tag, originPrice){
    return priceHandler[tag](originPrice);
}

Extract Variable

What: Replace a complex expression with a well‑named local variable.

Where: When an expression is hard to read or debug.

How:

// ===================Before Refactoring==================
function price(order) {
    return order.quantity * order.price -
        Math.max(0, order.quantity - 500) * order.price * 0.05 +
        Math.min(order.quantity * order.price * 0.1, 100);
}

// ===================After Refactoring===================
function price(order) {
    const basePrice = order.quantity * order.price;
    const quantityDiscount = Math.max(0, order.quantity - 500) * order.price * 0.05;
    const shipping = Math.min(basePrice * 0.1, 100);
    return basePrice - quantityDiscount + shipping;
}

Inline Variable

What: Remove a variable when its name does not add clarity.

Where: When the variable name is no more expressive than the expression itself.

How:

// ===================Before Refactoring==================
let basePrice = anOrder.basePrice;
return (basePrice > 1000);

// ===================After Refactoring===================
return anOrder.basePrice > 1000;

Encapsulate Variable

What: Hide a variable behind getter/setter functions.

Where: When mutable data is accessed from multiple places.

How:

// ===================Before Refactoring==================
let defaultOwner = {firstName: "Martin", lastName: "Fowler"};
spaceship.owner = defaultOwner;
defaultOwner = {firstName: "Rebecca", lastName: "Parsons"};

// ===================After Refactoring===================
function getDefaultOwner(){ return defaultOwner; }
function setDefaultOwner(arg){ defaultOwner = arg; }
spaceship.owner = getDefaultOwner();
setDefaultOwner({firstName: "Rebecca", lastName: "Parsons"});

Split Phase

What: Divide a large block of behavior into sequential phases.

Where: When a piece of code handles two unrelated concerns.

How:

// ===================Before Refactoring==================
function priceOrder(product, quantity, shippingMethod) {
    const basePrice = product.basePrice * quantity;
    const discount = Math.max(quantity - product.discountThreshold, 0) * product.basePrice * product.discountRate;
    const shippingPerCase = (basePrice > shippingMethod.discountThreshold) ? shippingMethod.discountedFee : shippingMethod.feePerCase;
    const shippingCost = quantity * shippingPerCase;
    const price = basePrice - discount + shippingCost;
    return price;
}

// ===================After Refactoring===================
function priceOrder(product, quantity, shippingMethod) {
    const priceData = calculatePricingData(product, quantity);
    return applyShipping(priceData, shippingMethod);
}
function calculatePricingData(product, quantity) {
    const basePrice = product.basePrice * quantity;
    const discount = Math.max(quantity - product.discountThreshold, 0) * product.basePrice * product.discountRate;
    return {basePrice, quantity, discount};
}
function applyShipping(priceData, shippingMethod) {
    const shippingPerCase = (priceData.basePrice > shippingMethod.discountThreshold) ? shippingMethod.discountedFee : shippingMethod.feePerCase;
    const shippingCost = priceData.quantity * shippingPerCase;
    return priceData.basePrice - priceData.discount + shippingCost;
}

Split Loop

What: Separate a loop that does multiple things into distinct loops.

Where: When a single loop mixes unrelated responsibilities.

How:

// ===================Before Refactoring==================
let youngest = people[0] ? people[0].age : Infinity;
let totalSalary = 0;
for(const p of people){
    if(p.age < youngest) youngest = p.age; // find youngest
    totalSalary += p.salary;            // sum salaries
}
console.log(`youngestAge: ${youngest}, totalSalary: ${totalSalary}`);

// ===================After Refactoring===================
let totalSalary = 0;
for(const p of people){ totalSalary += p.salary; }
let youngest = people[0] ? people[0].age : Infinity;
for(const p of people){ if(p.age < youngest) youngest = p.age; }
console.log(`youngestAge: ${youngest}, totalSalary: ${totalSalary}`);

Split Variable

What: Divide a variable that holds multiple responsibilities into separate variables.

Where: When a variable is used for more than one logical purpose.

How:

// ===================Before Refactoring==================
let temp = 2 * (height + width);
console.log(temp);
temp = height * width;
console.log(temp);

// ===================After Refactoring===================
const perimeter = 2 * (height + width);
console.log(perimeter);
const area = height * width;
console.log(area);

Decompose Conditional Expression

What: Extract complex conditionals into separate functions.

Where: When a function contains intricate boolean logic.

How:

// ===================Before Refactoring==================
if(!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd))
    charge = quantity * plan.summerRate;
else
    charge = quantity * plan.regularRate + plan.regularServiceCharge;

// ===================After Refactoring===================
if(summer())
    charge = summerCharge();
else
    charge = regularCharge();
function summer(){ return !aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd); }
function summerCharge(){ return quantity * plan.summerRate; }
function regularCharge(){ return quantity * plan.regularRate + plan.regularServiceCharge; }

Combine Conditional Expressions

What: Merge multiple guard checks that lead to the same outcome.

Where: When several separate if‑statements all return the same value.

How:

// ===================Before Refactoring==================
if(anEmployee.seniority < 2) return 0;
if(anEmployee.monthsDisabled > 12) return 0;
if(anEmployee.isPartTime) return 0;

// ===================After Refactoring===================
if(isNotEligibleForDisability()) return 0;
function isNotEligibleForDisability(){
    return (anEmployee.seniority < 2) || (anEmployee.monthsDisabled > 12) || anEmployee.isPartTime;
}

Guard Clauses Instead of Nested Conditionals

What: Use early returns for rare conditions to simplify the main flow.

Where: When nested if‑else structures give equal weight to all branches.

How:

// ===================Before Refactoring==================
function payAmount(employee){
    let result;
    if(employee.isSeparated){
        result = {amount:0, reasonCode:"SEP"};
    } else {
        if(employee.isRetired){
            result = {amount:0, reasonCode:"RET"};
        } else {
            result = someFinalComputation();
        }
    }
    return result;
}

// ===================After Refactoring===================
function payAmount(employee){
    if(employee.isSeparated) return {amount:0, reasonCode:"SEP"};
    if(employee.isRetired)   return {amount:0, reasonCode:"RET"};
    return someFinalComputation();
}

Separate Query and Modification Functions

What: Split a function that both returns a value and causes side effects.

Where: When a function mixes lookup logic with state‑changing actions.

How:

// ===================Before Refactoring==================
function alertForMiscreant(people){
    for(const p of people){
        if(p === "Don"){ setOffAlarms(); return "Don"; }
        if(p === "John"){ setOffAlarms(); return "John"; }
    }
    return "";
}
const found = alertForMiscreant(people);

// ===================After Refactoring===================
function findMiscreant(people){
    for(const p of people){
        if(p === "Don") return "Don";
        if(p === "John") return "John";
    }
    return "";
}
function alertForMiscreant(people){
    if(findMiscreant(people) !== "") setOffAlarms();
}
const found = findMiscreant(people);
alertForMiscreant(people);
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Software Engineeringrefactoringclean code
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.