メインコンテンツへ移動

เนื้อหาภาษาไทย / タイ語のコンテンツ

システムガイド 内容確認済み

Refactoring: Introduce Parameter Object

บทความนี้แนะนำเทคนิค Refactoring ที่เรียกว่า "Introduce Parameter Object" เพื่อแก้ปัญหาฟังก์ชันที่มี Parameter จำนวนมาก ซึ่งทำให้โค้ดอ่านและบำรุงรักษายาก อีกทั้...

Refactoring: Introduce Parameter Object

ในบทความที่แล้ว เราได้เรียนรู้เกี่ยวกับการแทนที่ตัวเลขที่ไม่มีความหมาย (Magic Number) ด้วยค่าคงที่ (Symbolic Constant) เพื่อให้โค้ดของเราอ่านง่ายขึ้น ในบทความนี้ เราจะมาเรียนรู้เทคนิค Refactoring อีกอย่างหนึ่งที่เรียกว่า "Introduce Parameter Object" ซึ่งจะช่วยเราจัดการกับฟังก์ชันที่มี Parameter จำนวนมากได้อย่างมีประสิทธิภาพ

ปัญหาของ Parameter List ยาวๆ

ลองจินตนาการว่าคุณมีฟังก์ชันที่รับ Parameter จำนวนมาก เช่น:

function calculateTotal(
    float $price,
    float $discount,
    float $taxRate,
    string $shippingAddress,
    string $billingAddress,
    string $couponCode = null
): float {
    // ... การคำนวณต่างๆ ...
}

ฟังก์ชันที่มี Parameter จำนวนมากเช่นนี้ มีข้อเสียหลายประการ:

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

เทคนิค "Introduce Parameter Object" จะช่วยแก้ปัญหาเหล่านี้ได้ โดยการรวม Parameter ที่เกี่ยวข้องเข้าด้วยกันเป็น Object เดียว

การสร้าง Parameter Object

ขั้นตอนแรกในการใช้เทคนิค "Introduce Parameter Object" คือการสร้าง Class ที่จะทำหน้าที่เป็น Parameter Object ตัวอย่างเช่น จากฟังก์ชัน calculateTotal ด้านบน เราสามารถสร้าง Class ที่ชื่อว่า OrderDetails ได้ดังนี้:

class OrderDetails
{
    public float $price;
    public float $discount;
    public float $taxRate;
    public string $shippingAddress;
    public string $billingAddress;
    public ?string $couponCode;

    public function __construct(
        float $price,
        float $discount,
        float $taxRate,
        string $shippingAddress,
        string $billingAddress,
        ?string $couponCode = null
    ) {
        $this->price = $price;
        $this->discount = $discount;
        $this->taxRate = $taxRate;
        $this->shippingAddress = $shippingAddress;
        $this->billingAddress = $billingAddress;
        $this->couponCode = $couponCode;
    }
}

ใน Class OrderDetails เราได้รวม Parameter ทั้งหมดจากฟังก์ชัน calculateTotal เข้าไว้ด้วยกัน โดยแต่ละ Parameter จะถูกกำหนดให้เป็น Property ของ Class

กรณีใช้งานจริง: การสร้าง Parameter Object ไม่จำเป็นต้องมี Property ทั้งหมดจาก Parameter เดิมเสมอไป เราสามารถเลือกเฉพาะ Parameter ที่เกี่ยวข้องและมีความสัมพันธ์กันอย่างใกล้ชิดมาใส่ใน Object ได้

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

การใช้งาน Parameter Object

เมื่อเรามี Parameter Object แล้ว เราสามารถแก้ไขฟังก์ชัน calculateTotal ให้รับ Object นี้เป็น Parameter ได้ดังนี้:

function calculateTotal(OrderDetails $orderDetails): float
{
    $price = $orderDetails->price;
    $discount = $orderDetails->discount;
    $taxRate = $orderDetails->taxRate;
    $shippingAddress = $orderDetails->shippingAddress;
    $billingAddress = $orderDetails->billingAddress;
    $couponCode = $orderDetails->couponCode;

    // ... การคำนวณต่างๆ โดยใช้ข้อมูลจาก $orderDetails ...
}

จะเห็นได้ว่าฟังก์ชัน calculateTotal ตอนนี้รับ Parameter เพียงตัวเดียวคือ OrderDetails ซึ่งเป็น Object ที่เก็บข้อมูลทั้งหมดที่จำเป็นสำหรับการคำนวณ

ตัวอย่างการใช้งาน:

$orderDetails = new OrderDetails(
    price: 100.00,
    discount: 10.00,
    taxRate: 0.07,
    shippingAddress: '123 Main St',
    billingAddress: '456 Oak Ave',
    couponCode: 'SAVE10'
);

$total = calculateTotal($orderDetails);

echo "Total: " . $total;

กรณีใช้งานจริง: การใช้ Parameter Object ทำให้เราสามารถเพิ่ม Validation Logic เข้าไปใน Class ได้ ตัวอย่างเช่น เราสามารถตรวจสอบได้ว่า price และ discount มีค่าเป็นบวกเสมอ

class OrderDetails
{
    // ...

    public function __construct(
        float $price,
        float $discount,
        float $taxRate,
        string $shippingAddress,
        string $billingAddress,
        ?string $couponCode = null
    ) {
        if ($price < 0) {
            throw new InvalidArgumentException("Price must be positive.");
        }
        $this->price = $price;
        $this->discount = $discount;
        $this->taxRate = $taxRate;
        $this->shippingAddress = $shippingAddress;
        $this->billingAddress = $billingAddress;
        $this->couponCode = $couponCode;
    }
}

ข้อผิดพลาดที่พบบ่อย: การเข้าถึง Property ของ Object โดยตรง (เช่น $orderDetails->price) อาจทำให้เกิดปัญหาได้ในอนาคต หากมีการเปลี่ยนแปลงโครงสร้างของ Object วิธีที่ดีกว่าคือการใช้ Getter Methods (เช่น $orderDetails->getPrice()) เพื่อห่อหุ้ม (Encapsulate) การเข้าถึง Property

ประโยชน์ที่ได้รับ

การใช้เทคนิค "Introduce Parameter Object" มีประโยชน์หลายประการ:

  • โค้ดอ่านง่ายขึ้น: ฟังก์ชันมี Parameter น้อยลง ทำให้ง่ายต่อการทำความเข้าใจ
  • โค้ดบำรุงรักษาง่ายขึ้น: การเปลี่ยนแปลง Parameter ทำได้ง่ายขึ้น เนื่องจากไม่ต้องแก้ไขทุกที่ที่เรียกใช้ฟังก์ชัน
  • ลดโอกาสผิดพลาด: การส่ง Parameter ผิดพลาดลดลง เนื่องจาก Parameter ถูกรวมเป็น Object เดียว
  • เพิ่มความยืดหยุ่น: สามารถเพิ่ม Validation Logic และ Business Logic เข้าไปใน Object ได้

สรุป

เทคนิค "Introduce Parameter Object" เป็นเครื่องมือที่มีประโยชน์ในการ Refactoring ฟังก์ชันที่มี Parameter จำนวนมาก การรวม Parameter ที่เกี่ยวข้องเข้าด้วยกันเป็น Object จะช่วยให้โค้ดของเราอ่านง่ายขึ้น บำรุงรักษาง่ายขึ้น และลดความเสี่ยงในการเกิดข้อผิดพลาด

ในบทความถัดไป เราจะมาเรียนรู้เทคนิค Refactoring อื่นที่เรียกว่า "Decompose Conditional" ซึ่งจะช่วยเราจัดการกับ Conditional Statements ที่ซับซ้อนได้อย่างมีประสิทธิภาพ

Office.in.th Custom Service

この構成をもとにシステムを開発・カスタマイズしたいですか?

Office.in.th は、エンタープライズ Web アプリケーション、API 連携、官民の業務管理システムの設計・開発を承り、長期的なサポートも提供します。

ソフトウェア開発サービスを見る