PlusMagi's Blog By Pitt Phunsanit Backend,Design Patterns PHP: การเลือกใช้ Design Patterns ที่เหมาะสม (เช่น Factory, Singleton, Strategy)

PHP: การเลือกใช้ Design Patterns ที่เหมาะสม (เช่น Factory, Singleton, Strategy)

ในฐานะ Senior Architect ด้านระบบ PHP การทำความเข้าใจ Design Patterns ไม่ใช่แค่การท่องจำโค้ด แต่คือการเรียนรู้ ‘วิธีแก้ปัญหา’ (Proven Solutions) ที่ผ่านการพิสูจน์แล้ว มันเปรียบเสมือนชุดเครื่องมือทางความคิดที่ช่วยให้เราเขียนโค้ดที่มีโครงสร้างชัดเจน, ยืดหยุ่นสูง (Flexible), และง่ายต่อการบำรุงรักษา (Maintainable) โดยเฉพาะอย่างยิ่งเมื่อระบบของเราต้องรองรับการขยายตัวและมีการเชื่อมต่อกับระบบฐานข้อมูลขนาดใหญ่ เช่น PostgreSQL

การใช้ Patterns อย่างถูกต้องจะช่วยให้เราหลีกเลี่ยงการเขียนโค้ดแบบ “God Object” และส่งเสริมหลักการ SOLID โดยเฉพาะ Single Responsibility Principle ทำให้เมื่อคุณต้องการเพิ่มฟีเจอร์ใหม่ เช่น การเปลี่ยนวิธีการประมวลผลคำสั่งซื้อ (Order Processing) คุณไม่ต้องไปแตะโค้ดส่วนอื่น ๆ ที่ทำงานอยู่แล้ว

1. Strategy Pattern: การกำหนดกลยุทธ์การทำงาน (Flexibility)

เมื่อคุณมีอัลกอริทึมหลายแบบที่สามารถสลับใช้ได้ตามบริบท เช่น การคำนวณภาษี หรือการเชื่อมต่อฐานข้อมูลด้วยวิธีการที่แตกต่างกัน (เช่น PDO หรือ PGSQL Extension) Strategy Pattern คือคำตอบที่ดีที่สุด

ในตัวอย่างนี้ เราจะจำลองการคำนวณราคาตามวิธีการชำระเงินที่หลากหลาย:

PHP

// 1. Interface/Abstract Class (Strategy) <code>
interface PaymentStrategy {
    public function calculate(float $amount): float;
}

// 2. Concrete Strategies (Implementation) <code>
class CreditCardPayment implements PaymentStrategy {
    public function calculate(float $amount): float {
        // สมมติว่าบัตรเครดิตมีค่าธรรมเนียม 2%
        return $amount * 1.02;
    }
}

class CashPayment implements PaymentStrategy {
    public function calculate(float $amount): float {
        // เงินสดไม่มีค่าธรรมเนียม
        return $amount;
    }
}

// 3. Context (Client) <code>
class ShoppingCart {
    private PaymentStrategy $strategy;

    public function setStrategy(PaymentStrategy $strategy) {
        $this->strategy = $strategy;
    }

    public function checkout(float $total): float {
        return $this->strategy->calculate($total);
    }
}

// Usage Example <code>
$cart = new ShoppingCart();
$cart->setStrategy(new CreditCardPayment());
$price1 = $cart->checkout(100.0);

$cart->setStrategy(new CashPayment());
$price2 = $cart->checkout(100.0);
// $price1 จะมากกว่า $price2

2. Factory Pattern: การสร้าง Object อย่างชาญฉลาด (Decoupling)

Factory Pattern ใช้เมื่อคุณไม่ต้องการให้โค้ดหลักของคุณรู้ว่าต้องสร้าง Object ชนิดใด แต่ต้องการให้มี ‘โรงงาน’ ที่รับผิดชอบการสร้าง Object นั้น ๆ โดยเฉพาะ เหมาะอย่างยิ่งในการจัดการ Connection Object ที่ต้องเลือกใช้ Driver ต่าง ๆ

PHP

class DatabaseFactory {
    public static function createConnection(string $type): ?object {
        if ($type === 'pgsql') {
            // ในชีวิตจริงคือการสร้าง PDO object สำหรับ PostgreSQL
            return new class { public function connect() { return 'Connected via PGSQL'; } };
        } elseif ($type === 'mysql') {
            return new class { public function connect() { return 'Connected via MySQL'; } };
        } else {
            return null; // ไม่รองรับ
        }
    }
}

// Usage Example <code>
$pgsqlConnection = DatabaseFactory::createConnection('pgsql');
if ($pgsqlConnection) {
    echo $pgsqlConnection->connect(); // Connected via PGSQL
}

3. Singleton Pattern: การควบคุม Instance เดียว (Resource Management)

Singleton Pattern รับประกันว่าคลาสของคุณจะมี Instance ได้เพียงตัวเดียวเท่านั้น เหมาะสำหรับ Resource ที่มีค่าใช้จ่ายในการสร้างสูง หรือต้องมีการเข้าถึงสถานะร่วมกันทั่วทั้งระบบ เช่น Connection Pool หรือ Logger

PHP

class DatabaseConnection {
    private static ?DatabaseConnection $instance = null;
    private function __construct() {
        // Logic สำหรับการเชื่อมต่อ PostgreSQL ครั้งแรก
        echo "[INFO] Establishing single PostgreSQL connection...\n";
    }

    public static function getInstance(): DatabaseConnection {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function executeQuery(string $query): void {
        echo "Executing query: " . substr($query, 0, 15) . "...\n";
    }
}

// Usage Example <code>
$conn1 = DatabaseConnection::getInstance();
$conn2 = DatabaseConnection::getInstance();
// $conn1 และ $conn2 จะเป็น Object ตัวเดียวกัน
$conn1->executeQuery('SELECT 1, 2, 3');

บทสรุป: การเลือกใช้ Pattern ที่เหมาะสม

การเลือกใช้ Design Pattern ไม่ใช่การทำตามตำรา แต่คือการวิเคราะห์ปัญหา (Problem Analysis) ก่อนเสมอ: หากคุณต้องการความยืดหยุ่นในการสลับพฤติกรรม ให้ใช้ Strategy; หากคุณต้องการสร้าง Object ที่หลากหลายจากจุดเดียว ให้ใช้ Factory; และหากคุณต้องการควบคุม Resource ให้มี Instance เดียวเท่านั้น ให้ใช้ Singleton

การนำ Patterns เหล่านี้มาใช้ร่วมกับการจัดการ Resource ของ PostgreSQL อย่างถูกต้อง จะช่วยยกระดับโค้ด PHP ของคุณให้เป็นระดับ Enterprise-Grade อย่างแท้จริง

Exit mobile version