เมธอดที่ดูแลรักษาง่ายควรสื่อความตั้งใจของผู้เขียนได้ชัดเจน ทั้งชื่อ ขั้นตอน และการใช้ตัวแปร เมื่ออ่านโค้ดแล้วต้องไล่แกะรายละเอียดจำนวนมาก กลุ่มเทคนิค Composing Methods ช่วยปรับโครงสร้างภายในเมธอดและแบ่งงานให้เหมาะสม โดยรักษาพฤติกรรมที่ผู้เรียกสังเกตได้ไว้เหมือนเดิม

info-refactoring-composing-methods-9-java

บทความนี้อธิบาย 9 เทคนิคตามหมวด Composing Methods ของ Refactoring.Guru พร้อมตัวอย่าง Java ที่เขียนขึ้นใหม่เพื่อการเรียนรู้ ตัวอย่างเป็นส่วนของคลาส ให้ใส่แต่ละตัวอย่างในคลาสแยกกัน และเลือกใช้เวอร์ชันก่อนหรือหลังทีละเวอร์ชัน ตัวอย่างไม่ได้ระบุเวอร์ชัน Java ล่าสุด และไม่ได้ผ่านการคอมไพล์ในสภาพแวดล้อมที่จัดทำบทความ

#1. Refactoring ต้องรักษาอะไรไว้บ้าง

การปรับโครงสร้างมีเป้าหมายให้โค้ดอ่าน เข้าใจ และแก้ไขได้ง่ายขึ้น โดยพฤติกรรมเดิมยังคงอยู่ เช่น ค่าที่คืนกลับ ข้อยกเว้น ลำดับการบันทึกข้อมูล และจำนวนครั้งที่เรียกบริการภายนอกตามสัญญาของระบบ

ก่อนแก้ไขควรมี regression tests ที่อธิบายพฤติกรรมปัจจุบัน เปลี่ยนครั้งละหนึ่งเรื่อง แล้วรันชุดทดสอบที่เกี่ยวข้อง หากพบข้อผิดพลาดของกฎธุรกิจ ให้แยกการแก้พฤติกรรมออกจากการปรับโครงสร้าง เพื่อให้ตรวจสอบผลของแต่ละการเปลี่ยนแปลงได้

เป้าหมายคือทำให้ความหมายชัดเจน ไม่มีกฎว่าทุกเมธอดต้องสั้นที่สุด หรือทุกนิพจน์ต้องถูกแยกเป็นเมธอด

#2. ตารางเลือกเทคนิค

เทคนิค สัญญาณที่พบ แนวทางหลัก
Extract Method โค้ดกลุ่มหนึ่งทำงานย่อยที่ตั้งชื่อได้ แยกเป็นเมธอดและเรียกใช้แทน
Inline Method เมธอดเพิ่มขั้นตอนการตามอ่านโดยไม่ได้เพิ่มความหมาย นำเนื้อหากลับไปไว้ที่จุดเรียก
Extract Variable นิพจน์หรือเงื่อนไขอ่านยาก ตั้งชื่อตัวแปรให้ผลลัพธ์ย่อย
Inline Temp ตัวแปรพักค่าเรียบง่ายและไม่ได้ช่วยสื่อความหมาย ใช้นิพจน์แทนตัวแปร
Replace Temp with Query การคำนวณควรใช้ซ้ำผ่านเมธอด ย้ายการคำนวณไปยังเมธอดคืนค่า
Split Temporary Variable ตัวแปรเดียวรับหลายหน้าที่ แยกตัวแปรตามความหมาย
Remove Assignments to Parameters พารามิเตอร์ถูกเขียนทับในเมธอด ใช้ตัวแปรภายในเก็บค่าที่ปรับแล้ว
Replace Method with Method Object เมธอดยาวและตัวแปรเกี่ยวพันกันจนแยกยาก สร้างออบเจ็กต์สำหรับการคำนวณ
Substitute Algorithm ขั้นตอนเดิมเข้าใจยากหรือมีวิธีที่เหมาะกว่า เปลี่ยนอัลกอริทึมภายใต้สัญญาเดิม

#3. Extract Method — แยกกลุ่มงานเป็นเมธอด

ปัญหา: เมธอดเดียวมีรายละเอียดหลายระดับ เช่น ทั้งจัดรูปแบบและแสดงผล

แนวทาง: เลือกกลุ่มคำสั่งที่มีหน้าที่เดียว ตั้งชื่อให้สื่อว่างานนั้นทำอะไร แล้วส่งข้อมูลที่ต้องใช้ผ่านพารามิเตอร์ หากมีผลลัพธ์ให้คืนกลับผ่าน return

#ก่อนปรับ

static void printReceipt(String customerName, double total) {
    System.out.println("=== RECEIPT ===");
    System.out.println("Customer: " + customerName);
    System.out.println("Total: " + total);
}

#หลังปรับ

static void printReceipt(String customerName, double total) {
    printHeader();
    printDetails(customerName, total);
}

private static void printHeader() {
    System.out.println("=== RECEIPT ===");
}

private static void printDetails(String customerName, double total) {
    System.out.println("Customer: " + customerName);
    System.out.println("Total: " + total);
}

เมธอดหลักแสดงลำดับงาน ส่วนรายละเอียดอยู่ในเมธอดย่อย ตัวอย่างสั้นนี้ใช้สาธิตการแยกขั้นตอน ในงานจริงไม่จำเป็นต้องแยก printHeader() หากชื่อใหม่ไม่ได้ช่วยให้เข้าใจงานมากขึ้น

ข้อควรระวัง: ตรวจว่าตัวแปรใดถูกอ่านหรือแก้ไขในส่วนที่จะย้าย และรักษาลำดับ side effects เช่น การพิมพ์หรือเขียนไฟล์

#4. Inline Method — รวมเนื้อหาเมธอดกลับสู่จุดเรียก

ปัญหา: การเรียกผ่านเมธอดอีกชั้นทำให้ต้องตามอ่าน แต่ชื่อเมธอดไม่ได้อธิบายเพิ่ม

แนวทาง: ใช้เนื้อหาของเมธอดแทนการเรียก เมื่อไม่มีจุดเรียกเหลือและไม่กระทบสัญญาภายนอกจึงลบเมธอดเดิม

#ก่อนปรับ

static int priority(int failedAttempts) {
    return check(failedAttempts) ? 2 : 1;
}

private static boolean check(int failedAttempts) {
    return failedAttempts >= 3;
}

#หลังปรับ

static int priority(int failedAttempts) {
    return failedAttempts >= 3 ? 2 : 1;
}

เงื่อนไขสั้นและตรงไปตรงมา จึงอ่านได้ทันทีโดยไม่ต้องเปิดเมธอด check() อีกแห่ง แต่หากชื่อเป็นแนวคิดธุรกิจที่มีความหมาย เช่น requiresManualReview() การเก็บเมธอดไว้ก็อาจช่วยให้ระบบเข้าใจง่ายกว่า

ข้อควรระวัง: อย่า inline โดยละเลยการ override หรือ dynamic dispatch และอย่าลบ public API ที่ผู้ใช้งานภายนอกยังเรียกอยู่ การย้ายเนื้อหาต้องรักษาจำนวนครั้งและลำดับการประเมินอาร์กิวเมนต์ด้วย

#5. Extract Variable — ตั้งชื่อให้ส่วนของนิพจน์

ปัญหา: ผู้อ่านต้องตีความสูตรหรือเงื่อนไขซ้ำทุกครั้ง

แนวทาง: สร้างตัวแปรที่ชื่ออธิบายความหมายของผลลัพธ์ โดยวางใกล้จุดใช้งาน

#ก่อนปรับ

static boolean eligible(int quantity, double unitPrice, int memberYears) {
    return quantity * unitPrice >= 2000 && memberYears >= 2;
}

#หลังปรับ

static boolean eligible(int quantity, double unitPrice, int memberYears) {
    final double subtotal = quantity * unitPrice;
    final boolean meetsSpendingThreshold = subtotal >= 2000;
    final boolean isLongTermMember = memberYears >= 2;
    return meetsSpendingThreshold && isLongTermMember;
}

ชื่อทำให้เห็นว่ามีเงื่อนไขด้านยอดซื้อและอายุสมาชิก เหมาะกับสูตรที่มีหลายส่วนหรือค่าที่ต้องอธิบายความหมาย

ข้อควรระวัง: การย้ายนิพจน์ออกจาก && หรือ || อาจทำให้ส่วนที่เดิมถูกข้ามด้วย short-circuit กลับถูกประเมิน เช่น user != null && user.isActive() จะแยกเรียก user.isActive() ล่วงหน้าไม่ได้ ตัวอย่างนี้ใช้การคำนวณจาก primitive จึงไม่มีปัญหาดังกล่าว

#6. Inline Temp — ยุบตัวแปรพักค่าที่ไม่จำเป็น

ปัญหา: ตัวแปรเก็บนิพจน์ง่าย ๆ เพียงเพื่อคืนค่าทันที และชื่อไม่ได้ช่วยอธิบาย

แนวทาง: นำนิพจน์ไปใช้ตรงจุดที่อ้างถึงตัวแปร แล้วลบตัวแปร

#ก่อนปรับ

static int itemCount(int boxes, int itemsPerBox) {
    int value = boxes * itemsPerBox;
    return value;
}

#หลังปรับ

static int itemCount(int boxes, int itemsPerBox) {
    return boxes * itemsPerBox;
}

ข้อควรระวัง: ตัวแปรที่ใช้ครั้งเดียวก็อาจมีประโยชน์ หากชื่อช่วยอธิบายสูตร นอกจากนี้ value = fetchData() ที่ถูกอ้างถึงหลายครั้งไม่ควรถูกแทนด้วยการเรียก fetchData() ทุกจุด เพราะอาจเพิ่มการทำงาน ผลข้างเคียง หรือได้คนละค่า

#7. Replace Temp with Query — ย้ายการคำนวณเป็นเมธอดคืนค่า

ปัญหา: การคำนวณที่มีความหมายถูกผูกไว้กับตัวแปรภายในเมธอด ทำให้ส่วนอื่นใช้ซ้ำได้ยาก

แนวทาง: ย้ายการคำนวณไปเป็น query method แล้วเรียกเมธอดนั้นจากจุดใช้งาน โดย query ที่นำมาใช้ซ้ำควรไม่มีผลข้างเคียง

#ก่อนปรับ

static final class OrderPrice {
    private final int quantity;
    private final double unitPrice;

    OrderPrice(int quantity, double unitPrice) {
        this.quantity = quantity;
        this.unitPrice = unitPrice;
    }

    double discountedTotal() {
        double subtotal = quantity * unitPrice;
        return subtotal >= 2000 ? subtotal * 0.90 : subtotal;
    }
}

#หลังปรับ

static final class OrderPrice {
    private final int quantity;
    private final double unitPrice;

    OrderPrice(int quantity, double unitPrice) {
        this.quantity = quantity;
        this.unitPrice = unitPrice;
    }

    double subtotal() {
        return quantity * unitPrice;
    }

    double discountedTotal() {
        return subtotal() >= 2000 ? subtotal() * 0.90 : subtotal();
    }
}

เมธอด subtotal() ทำให้การคำนวณใช้ซ้ำได้ ตัวอย่างมีฟิลด์ที่ไม่เปลี่ยนค่าและคำนวณง่าย การเรียกซ้ำจึงไม่เปลี่ยนผล แต่จำนวนครั้งที่คำนวณเพิ่มขึ้น

ข้อควรระวัง: หาก query ทำงานแพง เช่น รวมข้อมูลจำนวนมาก หรืออ่านข้อมูลที่เปลี่ยนระหว่างการเรียก ควรประเมินต้นทุนและความสอดคล้องของข้อมูล การเก็บผล query ไว้ในตัวแปรเฉพาะรอบงานยังเป็นทางเลือกที่เหมาะสมได้

#8. Split Temporary Variable — แยกตัวแปรตามหน้าที่

ปัญหา: ตัวแปรเดียวเปลี่ยนความหมายไปมาภายในเมธอด

แนวทาง: สร้างตัวแปรใหม่ให้แต่ละแนวคิด ใช้ชื่อที่ตรงกับข้อมูล และใช้ final เมื่อไม่ต้องเปลี่ยนค่า

#ก่อนปรับ

static void printRectangle(double width, double height) {
    double result = 2 * (width + height);
    System.out.println("Perimeter: " + result);
    result = width * height;
    System.out.println("Area: " + result);
}

#หลังปรับ

static void printRectangle(double width, double height) {
    final double perimeter = 2 * (width + height);
    System.out.println("Perimeter: " + perimeter);
    final double area = width * height;
    System.out.println("Area: " + area);
}

ผู้อ่านไม่ต้องตามว่าขณะนี้ result หมายถึงค่าประเภทใด

ข้อควรระวัง: ตัวนับลูปและตัวสะสม เช่น sum += value มีหน้าที่เดิมตลอดการใช้งาน การเปลี่ยนค่าหลายครั้งจึงไม่ได้เป็นเหตุให้ต้องแยกตัวแปรเสมอไป

#9. Remove Assignments to Parameters — เก็บค่าที่ปรับแล้วในตัวแปรภายใน

ปัญหา: เมธอดเขียนทับพารามิเตอร์จนแยกค่าเริ่มต้นกับค่าระหว่างคำนวณได้ยาก

แนวทาง: ใช้ตัวแปรภายในสำหรับค่าที่ผ่านการปรับ และเก็บพารามิเตอร์ไว้สื่อถึงอินพุตเดิม

#ก่อนปรับ

static double applyDiscount(double price, boolean member) {
    if (member) {
        price = price * 0.90;
    }
    return price;
}

#หลังปรับ

static double applyDiscount(final double price, boolean member) {
    double discountedPrice = price;
    if (member) {
        discountedPrice = price * 0.90;
    }
    return discountedPrice;
}

ใน Java การส่งพารามิเตอร์เป็น pass-by-value การกำหนด price ใหม่ในตัวอย่างแรกไม่ได้เปลี่ยนตัวแปร primitive ของผู้เรียก ประโยชน์ของการปรับครั้งนี้จึงอยู่ที่ความชัดเจนของข้อมูลภายในเมธอด

สำหรับพารามิเตอร์ออบเจ็กต์ การกำหนด reference ใหม่กับการแก้สถานะของออบเจ็กต์เป็นคนละเรื่อง final ป้องกันการกำหนดพารามิเตอร์ใหม่ แต่ไม่ได้ทำให้ออบเจ็กต์ immutable และการคัดลอก reference ไปยังตัวแปรใหม่ก็ไม่ได้สร้างสำเนาออบเจ็กต์

#10. Replace Method with Method Object — สร้างออบเจ็กต์สำหรับงานคำนวณ

ปัญหา: เมธอดมีตัวแปรระหว่างทางเกี่ยวพันกันมาก การใช้ Extract Method ทันทีอาจสร้างพารามิเตอร์จำนวนมาก

แนวทาง: ย้ายงานไปยังคลาสเฉพาะ ส่งอินพุตผ่าน constructor และย้ายสถานะระหว่างคำนวณที่จำเป็นไปเป็นฟิลด์ จากนั้นแบ่งเป็นเมธอดย่อยภายในคลาสนั้น

#ก่อนปรับ

static double netPay(int hours, double hourlyRate, double allowance) {
    int regularHours = Math.min(hours, 40);
    int overtimeHours = Math.max(hours - 40, 0);
    double regularPay = regularHours * hourlyRate;
    double overtimePay = overtimeHours * hourlyRate * 1.5;
    double grossPay = regularPay + overtimePay + allowance;
    double taxablePay = Math.max(grossPay - 1000, 0);
    double tax = taxablePay * 0.10;
    return grossPay - tax;
}

#หลังปรับ

static double netPay(int hours, double hourlyRate, double allowance) {
    return new PayCalculation(hours, hourlyRate, allowance).compute();
}

private static final class PayCalculation {
    private final int hours;
    private final double hourlyRate;
    private final double allowance;
    private double grossPay;
    private double taxablePay;

    PayCalculation(int hours, double hourlyRate, double allowance) {
        this.hours = hours;
        this.hourlyRate = hourlyRate;
        this.allowance = allowance;
    }

    double compute() {
        calculateGrossPay();
        calculateTaxablePay();
        return grossPay - taxablePay * 0.10;
    }

    private void calculateGrossPay() {
        int regularHours = Math.min(hours, 40);
        int overtimeHours = Math.max(hours - 40, 0);
        double regularPay = regularHours * hourlyRate;
        double overtimePay = overtimeHours * hourlyRate * 1.5;
        grossPay = regularPay + overtimePay + allowance;
    }

    private void calculateTaxablePay() {
        taxablePay = Math.max(grossPay - 1000, 0);
    }
}

ตัวอย่างย่อแสดงการย้ายสถานะการคำนวณออกจากเมธอดเดิม สำหรับงานจริงที่สั้นเท่านี้ Extract Method อาจเพียงพอ Method Object เหมาะเมื่อการเกี่ยวพันของตัวแปรทำให้การแยกเมธอดแบบปกติยุ่งยากจริง ๆ

ข้อควรระวัง: สร้างออบเจ็กต์การคำนวณใหม่สำหรับแต่ละงานตามตัวอย่าง ไม่ใช้สถานะ mutable ร่วมกันระหว่างคำขอพร้อมกัน คลาสนี้เป็นออบเจ็กต์ช่วยคำนวณ ไม่จำเป็นต้องพัฒนาเป็นระบบ Command Pattern เพิ่มเติม

สูตรเงินเดือนเป็นกติกาสมมติเพื่อสาธิตโครงสร้างเท่านั้น ตัวอย่างใช้ double เพื่อให้อ่านง่าย ระบบการเงินจริงควรกำหนดความแม่นยำและกฎการปัดเศษอย่างชัดเจน เช่น ออกแบบด้วย BigDecimal การเปลี่ยนชนิดตัวเลขควรทำเป็นอีกงานหนึ่ง เพราะอาจเปลี่ยนผลลัพธ์เดิม

#11. Substitute Algorithm — เปลี่ยนขั้นตอนโดยรักษาสัญญาเดิม

ปัญหา: อัลกอริทึมเดิมยาว เข้าใจยาก หรือมีไลบรารีที่แสดงเจตนาได้ชัดกว่า

แนวทาง: ระบุอินพุต เอาต์พุต และกรณีขอบให้ชัด แล้วแทนที่เนื้อหาภายในเมธอดด้วยวิธีใหม่ที่ให้พฤติกรรมตามสัญญาเดิม

#ก่อนปรับ

static int maximum(int[] values) {
    if (values.length == 0) {
        throw new IllegalArgumentException("values must not be empty");
    }
    int max = values[0];
    for (int i = 1; i < values.length; i++) {
        if (values[i] > max) {
            max = values[i];
        }
    }
    return max;
}

#หลังปรับ

static int maximum(int[] values) {
    return java.util.Arrays.stream(values)
        .max()
        .orElseThrow(() ->
            new IllegalArgumentException("values must not be empty"));
}

ทั้งสองแบบคืนค่าสูงสุด ไม่แก้ไขอาร์เรย์ และโยน IllegalArgumentException พร้อมข้อความเดิมเมื่ออาร์เรย์ว่าง อินพุต null ทำให้ทั้งสองแบบเกิด NullPointerException แต่รายละเอียดข้อความหรือ stack trace อาจต่างกัน หากระบบถือรายละเอียดเหล่านี้เป็นสัญญา ต้องตรวจเพิ่ม

ทั้งสองวิธีใช้เวลา O(n) ตัวอย่างนี้สาธิตการแทนขั้นตอนด้วยไลบรารีเพื่อสื่อเจตนา ไม่ได้ยืนยันว่า Stream เร็วกว่า loop

ข้อควรระวัง: ตรวจลำดับผลลัพธ์ ค่าซ้ำ null ข้อยกเว้น การแก้ข้อมูลต้นฉบับ และ precision ตามประเภทงาน หากเป้าหมายคือความเร็ว ให้ benchmark ด้วยข้อมูลที่เป็นตัวแทนของการใช้งานจริง

#12. เทคนิคที่ดูตรงข้ามกัน เลือกอย่างไร

ตัวเลือก เลือกฝั่งแรกเมื่อ เลือกฝั่งหลังเมื่อ
Extract Method / Inline Method ชื่อเมธอดซ่อนรายละเอียดและอธิบายงานได้ดี การเรียกเพิ่มภาระตามอ่านโดยไม่มีความหมายเพิ่ม
Extract Variable / Inline Temp ชื่อตัวแปรช่วยตีความสูตร นิพจน์เดิมชัดเจนและตัวแปรไม่เพิ่มข้อมูล
Extract Variable / Replace Temp with Query ต้องการตั้งชื่อผลลัพธ์ในบริบทเฉพาะจุด ต้องการให้การคำนวณมีชื่อและใช้ซ้ำผ่านเมธอด
Extract Method / Method Object ส่งข้อมูลผ่านพารามิเตอร์และคืนค่าได้ตรงไปตรงมา สถานะระหว่างทางเกี่ยวพันมากจนแยกยาก

การเลือกขึ้นอยู่กับบริบทเดียวกันได้หลายแบบ เช่น subtotal() อาจเป็น query ที่ดี ขณะที่ final double subtotal = order.subtotal(); ก็เหมาะเมื่ออยากใช้ค่าหนึ่งชุดตลอดรอบงาน

#13. ขั้นตอนฝึกปฏิบัติ

  1. เลือกเมธอดที่อ่านยากหนึ่งเมธอด และเขียนพฤติกรรมที่ต้องรักษาไว้
  2. เตรียม regression tests โดยเน้นอินพุตปกติและขอบเขตเงื่อนไข
  3. ระบุปัญหาเฉพาะ เช่น ตัวแปรหลายหน้าที่ หรือนิพจน์ไม่สื่อความหมาย
  4. เลือกหนึ่งเทคนิค เปลี่ยนขนาดเล็ก แล้วรันทดสอบ
  5. อ่านโค้ดจากมุมผู้ดูแลคนถัดไป ตรวจว่าชื่อช่วยให้เข้าใจหรือไม่
  6. ทำซ้ำเท่าที่จำเป็น และบันทึกแต่ละการเปลี่ยนแปลงให้ตรวจสอบได้

กรณีทดสอบแนะนำสำหรับตัวอย่างในบทความ (เป็นแผนทดสอบ ยังไม่ได้รัน):

ตัวอย่าง อินพุตที่ควรครอบคลุม สิ่งที่ตรวจ
Receipt ชื่อทั่วไป ชื่อว่าง และ null ข้อความและลำดับบรรทัดเหมือนเดิม
Priority จำนวนครั้ง 2, 3, 4 ค่าก่อนขอบเขตและที่ขอบเขต
Eligibility ยอด 1999, 2000 และอายุสมาชิก 1, 2 ต้องผ่านทั้งสองเงื่อนไข
Item count จำนวนกล่อง 0 และค่าบวก ผลคูณเหมือนเดิม
Order price ยอด 1999, 2000, 2001 ส่วนลดเริ่มที่ยอด 2000
Rectangle ด้านเป็น 0 และค่าบวก เส้นรอบรูป พื้นที่ และลำดับพิมพ์
Discount สมาชิกและบุคคลทั่วไป ส่วนลดและค่าของตัวแปรฝั่งผู้เรียก
Pay calculation ชั่วโมง 0, 40, 41 และรายได้คร่อม 1000 OT และฐานภาษีสมมติ
Maximum ค่าติดลบ ค่าซ้ำ ค่าเดียว อาร์เรย์ว่าง และ null ผลลัพธ์ ข้อยกเว้น และอาร์เรย์ไม่ถูกแก้

สำหรับตัวเลขทศนิยม ให้กำหนดเกณฑ์เปรียบเทียบที่เหมาะสม และตรวจว่ามีการเปลี่ยนลำดับคำนวณจนกระทบผลหรือไม่ การเพิ่ม validation ใหม่ระหว่าง refactoring ก็อาจเปลี่ยนพฤติกรรม จึงควรแยกพิจารณา

#14. ประเด็นสำหรับการสอนและ Code Review

  • ชื่อใหม่บอกเจตนาหรือเพียงย้ายความซับซ้อนไปอีกที่?
  • การใช้ตัวแปรสะท้อนความหมายเดียวตลอดช่วงชีวิตหรือไม่?
  • การประเมินนิพจน์ จำนวนครั้งที่เรียก และ side effects ยังเหมือนเดิมหรือไม่?
  • การปรับแตะ public API, inheritance หรือ shared state หรือไม่?
  • มีหลักฐานจาก regression tests รองรับการรักษาพฤติกรรมหรือยัง?

Composing Methods ช่วยให้แต่ละขั้นตอนและข้อมูลภายในเมธอดมีความหมายชัดขึ้น การแยกหรือรวมโค้ดควรตัดสินจากความเข้าใจที่เพิ่มขึ้นและพฤติกรรมที่ตรวจสอบได้

#แหล่งอ้างอิง

คำอธิบายแนวคิดเรียบเรียงภาษาไทยจากหน้าต่อไปนี้ ส่วนตัวอย่าง Java และข้อสังเกตในการประยุกต์เขียนเพิ่มเติมสำหรับบทความนี้

  1. Extract Method — Refactoring.Guru
  2. Inline Method — Refactoring.Guru
  3. Extract Variable — Refactoring.Guru
  4. Inline Temp — Refactoring.Guru
  5. Replace Temp with Query — Refactoring.Guru
  6. Split Temporary Variable — Refactoring.Guru
  7. Remove Assignments to Parameters — Refactoring.Guru
  8. Replace Method with Method Object — Refactoring.Guru
  9. Substitute Algorithm — Refactoring.Guru