Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

Strategy Pattern: เลือก Algorithm ใน Runtime

บทความนี้แนะนำ Strategy Pattern ซึ่งเป็น Design Pattern ที่ช่วยให้เราสามารถเลือก Algorithm ที่ต้องการใช้งานได้ในขณะที่โปรแกรมกำลังทำงาน (Runtime) โดยไม่ต้องแก้ไ...

Strategy Pattern: เลือก Algorithm ใน Runtime

จากบทที่แล้วที่เราได้เรียนรู้เกี่ยวกับ Factory Pattern ที่ช่วยให้เราสร้าง Object ได้อย่างยืดหยุ่น โดยไม่ต้องระบุ Class ที่ต้องการสร้างโดยตรง ในบทนี้ เราจะมาทำความรู้จักกับอีกหนึ่ง Design Pattern ที่มีประโยชน์อย่างมาก นั่นคือ Strategy Pattern ที่จะช่วยให้เราสามารถเลือก Algorithm หรือพฤติกรรมที่ต้องการใช้งานได้ในขณะที่โปรแกรมกำลังทำงาน (Runtime) โดยไม่ต้องแก้ไขโค้ดหลัก

Strategy Pattern คืออะไร?

Strategy Pattern เป็น Design Pattern ประเภท Behavioral ที่ช่วยให้เรากำหนดกลุ่มของ Algorithm ที่สามารถสลับเปลี่ยนกันได้ และทำให้ Client สามารถเลือก Algorithm ที่ต้องการใช้งานได้ในขณะที่โปรแกรมกำลังทำงาน โดยไม่ต้องแก้ไขโค้ดของ Client เอง

หลักการทำงานของ Strategy Pattern:

  • กำหนด Interface หรือ Abstract Class ที่เป็นตัวกลางสำหรับ Algorithm ทั้งหมด
  • สร้าง Class ที่ Implement Interface หรือสืบทอด Abstract Class เพื่อเป็นตัวแทนของแต่ละ Algorithm
  • สร้าง Context Class ที่เก็บ Algorithm ที่เลือกใช้งาน และมี Method สำหรับเรียกใช้งาน Algorithm นั้น
  • Client สามารถเลือก Algorithm ที่ต้องการใช้งาน และกำหนดให้กับ Context Class

ทำไมต้องใช้ Strategy Pattern?

การใช้ Strategy Pattern มีข้อดีหลายประการ:

  • ความยืดหยุ่น: สามารถสลับเปลี่ยน Algorithm ได้ง่าย โดยไม่ต้องแก้ไขโค้ดหลัก
  • การแยกส่วน: Algorithm แต่ละตัวถูกแยกออกเป็น Class ทำให้โค้ดมีความชัดเจนและง่ายต่อการบำรุงรักษา
  • การ Reuse: Algorithm สามารถนำกลับมาใช้ใหม่ได้ใน Context Class อื่นๆ
  • ลดความซับซ้อน: ช่วยลดความซับซ้อนของโค้ด โดยการแยก Algorithm ออกจาก Context Class

การ Implement Strategy Pattern ใน PHP

เพื่อให้เข้าใจ Strategy Pattern มากยิ่งขึ้น เรามาดูตัวอย่างการ Implement ใน PHP กัน

ตัวอย่าง: ระบบการคำนวณภาษี

สมมติว่าเรามีระบบที่ต้องคำนวณภาษี โดยมี Algorithm การคำนวณภาษีหลายแบบ เช่น ภาษีมูลค่าเพิ่ม (VAT), ภาษีหัก ณ ที่จ่าย (Withholding Tax), และภาษีเงินได้บุคคลธรรมดา (Personal Income Tax) เราสามารถใช้ Strategy Pattern เพื่อให้ระบบของเราสามารถเลือก Algorithm การคำนวณภาษีที่เหมาะสมได้ใน Runtime

1. สร้าง Interface สำหรับ Strategy:

interface TaxStrategy {
    public function calculateTax(float $amount): float;
}

Interface TaxStrategy กำหนด Method calculateTax() ที่รับจำนวนเงินเป็น Parameter และคืนค่าภาษีที่คำนวณได้

2. สร้าง Class สำหรับแต่ละ Strategy:

class VATStrategy implements TaxStrategy {
    private float $vatRate;

    public function __construct(float $vatRate) {
        $this->vatRate = $vatRate;
    }

    public function calculateTax(float $amount): float {
        return $amount * $this->vatRate;
    }
}

class WithholdingTaxStrategy implements TaxStrategy {
    private float $withholdingRate;

    public function __construct(float $withholdingRate) {
        $this->withholdingRate = $withholdingRate;
    }

    public function calculateTax(float $amount): float {
        return $amount * $this->withholdingRate;
    }
}

Class VATStrategy และ WithholdingTaxStrategy Implement Interface TaxStrategy และกำหนด Algorithm การคำนวณภาษีของตัวเอง

3. สร้าง Context Class:

class TaxCalculator {
    private TaxStrategy $taxStrategy;

    public function __construct(TaxStrategy $taxStrategy) {
        $this->taxStrategy = $taxStrategy;
    }

    public function setTaxStrategy(TaxStrategy $taxStrategy): void {
        $this->taxStrategy = $taxStrategy;
    }

    public function calculateTax(float $amount): float {
        return $this->taxStrategy->calculateTax($amount);
    }
}

Class TaxCalculator เป็น Context Class ที่เก็บ Instance ของ TaxStrategy และมี Method calculateTax() ที่เรียกใช้งาน Algorithm การคำนวณภาษีของ Strategy ที่เลือกใช้งาน

4. ใช้งาน Strategy Pattern:

// เลือก Strategy การคำนวณภาษี
$vatStrategy = new VATStrategy(0.07); // VAT 7%
$withholdingTaxStrategy = new WithholdingTaxStrategy(0.03); // Withholding Tax 3%

// สร้าง TaxCalculator และกำหนด Strategy
$taxCalculator = new TaxCalculator($vatStrategy);

// คำนวณภาษี
$amount = 1000;
$vatTax = $taxCalculator->calculateTax($amount);
echo "VAT Tax: " . $vatTax . "\n"; // Output: VAT Tax: 70

// เปลี่ยน Strategy
$taxCalculator->setTaxStrategy($withholdingTaxStrategy);
$withholdingTax = $taxCalculator->calculateTax($amount);
echo "Withholding Tax: " . $withholdingTax . "\n"; // Output: Withholding Tax: 30

จากตัวอย่าง เราสามารถสลับเปลี่ยน Algorithm การคำนวณภาษีได้ง่ายๆ โดยการกำหนด Strategy ใหม่ให้กับ TaxCalculator โดยไม่ต้องแก้ไขโค้ดของ TaxCalculator เอง

ข้อดีและข้อเสียของ Strategy Pattern

ข้อดี:

  • Open/Closed Principle: สามารถเพิ่ม Algorithm ใหม่ได้ โดยไม่ต้องแก้ไขโค้ดที่มีอยู่
  • Single Responsibility Principle: Algorithm แต่ละตัวถูกแยกออกเป็น Class ทำให้โค้ดมีความชัดเจน
  • ความยืดหยุ่น: สามารถสลับเปลี่ยน Algorithm ได้ง่ายใน Runtime

ข้อเสีย:

  • ความซับซ้อน: อาจทำให้โค้ดมีความซับซ้อนมากขึ้น หากมี Strategy จำนวนมาก
  • Client ต้องรู้ Strategy ที่มี: Client ต้องทราบ Algorithm ที่มีอยู่ เพื่อที่จะเลือกใช้งานได้ถูกต้อง

เหตุผลเชิงออกแบบ, Trade-offs, และแนวปฏิบัติที่ดี

  • การเลือก Strategy: การเลือก Strategy ที่เหมาะสมขึ้นอยู่กับความต้องการของระบบ อาจใช้ Factory Pattern ร่วมกับ Strategy Pattern เพื่อช่วยในการสร้าง Strategy Instance
  • การจัดการ Strategy: หากมี Strategy จำนวนมาก อาจใช้ Service Locator หรือ Dependency Injection Container เพื่อช่วยในการจัดการ Strategy Instance
  • การทดสอบ: ควรทดสอบ Algorithm แต่ละตัวอย่างละเอียด เพื่อให้มั่นใจว่าทำงานได้อย่างถูกต้อง
  • Trade-offs: Strategy Pattern เพิ่มความยืดหยุ่น แต่ก็เพิ่มความซับซ้อนของโค้ดด้วย ควรพิจารณาความเหมาะสมกับขนาดและความซับซ้อนของระบบ

สรุป

Strategy Pattern เป็น Design Pattern ที่มีประโยชน์อย่างมากในการจัดการ Algorithm ที่สามารถสลับเปลี่ยนกันได้ ช่วยให้โค้ดมีความยืดหยุ่น ลดความซับซ้อน และง่ายต่อการบำรุงรักษา ในบทถัดไป เราจะมาเรียนรู้เกี่ยวกับ Observer Pattern ที่ช่วยให้เราสามารถแจ้งเตือน Object อื่นๆ เมื่อมีการเปลี่ยนแปลงเกิดขึ้น

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service