SOLID Principles คืออะไร?
ถ้าคุณเป็น PHP Developer ที่ต้องการเขียนโค้ดให้ดีขึ้น มีโครงสร้างที่ชัดเจน และง่ายต่อการดูแล (maintain) SOLID Principles คือแนวคิดที่คุณต้องรู้!
SOLID เป็นชุดของ 5 หลักการออกแบบเชิงวัตถุ (OOP) ที่ช่วยให้โค้ดของคุณ อ่านง่าย, ขยายได้, และลดบั๊กในอนาคต โดยคำว่า SOLID มาจากอักษรตัวแรกของ 5 หลักการดังนี้:
- S – Single Responsibility Principle (SRP)
- O – Open/Closed Principle (OCP)
- L – Liskov Substitution Principle (LSP)
- I – Interface Segregation Principle (ISP)
- D – Dependency Inversion Principle (DIP)
ในบทความนี้ เราจะมาดูกันว่าแต่ละหลักการทำงานยังไง และเราจะใช้มันกับ PHP ได้ยังไง
1. Single Responsibility Principle (SRP) - หนึ่งคลาส หนึ่งหน้าที่
หลักการ:
"A class should have only one reason to change."
(คลาสควรมีเหตุผลเดียวที่ต้องเปลี่ยนแปลง)
แปลว่า: คลาสหนึ่งควรมีหน้าที่เดียว ไม่ควรทำหลายอย่างในที่เดียวกัน
❌ ตัวอย่างที่ไม่ดี:
class User {
public function saveToDatabase() {
// บันทึกข้อมูลลง Database
}
public function sendEmail() {
// ส่งอีเมลแจ้งเตือน
}
}
User ควรรับผิดชอบเฉพาะข้อมูลของผู้ใช้ ไม่ควรจัดการเรื่อง Database หรือ Email
✅ วิธีแก้:
class UserRepository {
public function save(User $user) {
// บันทึกข้อมูลลง Database
}
}
class EmailService {
public function send(User $user) {
// ส่งอีเมลแจ้งเตือน
}
}
ข้อดีของ SRP:
- แยกโค้ดตามหน้าที่ ทำให้แก้ไขง่าย
- ลดผลกระทบเมื่อเปลี่ยนแปลงโค้ด
2. Open/Closed Principle (OCP) - เปิดสำหรับขยาย ปิดสำหรับแก้ไข
หลักการ:
"Software entities should be open for extension but closed for modification."
(โค้ดควรเปิดให้ขยาย แต่ปิดสำหรับการแก้ไข)
แปลว่า: เราควรออกแบบโค้ดให้เพิ่มฟีเจอร์ใหม่ได้โดยไม่ต้องแก้ไขโค้ดเก่า
❌ ตัวอย่างที่ไม่ดี:
class Payment {
public function pay($method) {
if ($method == "credit_card") {
// จ่ายผ่านบัตรเครดิต
} elseif ($method == "paypal") {
// จ่ายผ่าน PayPal
}
}
}
ถ้าอยากเพิ่มวิธีชำระเงินใหม่ เราต้องไปแก้ไขโค้ดเดิม ซึ่งไม่ดีเลย
✅ วิธีแก้: ใช้ Polymorphism
interface PaymentMethod {
public function pay();
}
class CreditCardPayment implements PaymentMethod {
public function pay() {
// จ่ายผ่านบัตรเครดิต
}
}
class PayPalPayment implements PaymentMethod {
public function pay() {
// จ่ายผ่าน PayPal
}
}
class PaymentProcessor {
public function process(PaymentMethod $paymentMethod) {
$paymentMethod->pay();
}
}
ข้อดีของ OCP:
- เพิ่มวิธีชำระเงินใหม่ได้ง่าย โดยไม่ต้องแก้โค้ดเดิม
- ลดโอกาสเกิดบั๊กจากการแก้ไขโค้ด
3. Liskov Substitution Principle (LSP) - ใช้แทนกันได้โดยไม่พัง
หลักการ:
"Objects of a derived class must be substitutable for objects of the base class."
(คลาสลูกควรใช้แทนคลาสแม่ได้โดยไม่ทำให้โปรแกรมพัง)
❌ ตัวอย่างที่ไม่ดี:
class Bird {
public function fly() {
return "บินไปเลย!";
}
}
class Penguin extends Bird {
public function fly() {
throw new Exception("เพนกวินบินไม่ได้!");
}
}
Penguin เป็น Bird แต่ดันบินไม่ได้ ทำให้โปรแกรมอาจพังเมื่อเรียก fly()
✅ วิธีแก้: แยก Bird ออกเป็น FlyingBird และ NonFlyingBird
abstract class Bird {}
class FlyingBird extends Bird {
public function fly() {
return "บินไปเลย!";
}
}
class Penguin extends Bird {
public function swim() {
return "ว่ายน้ำ!";
}
}
ข้อดีของ LSP:
- ใช้คลาสลูกแทนคลาสแม่ได้อย่างปลอดภัย
- ลดปัญหาบั๊กที่เกิดจากพฤติกรรมที่ไม่คาดคิด
4. Interface Segregation Principle (ISP) - ใช้ Interface ให้เหมาะสม
หลักการ:
"Clients should not be forced to depend on methods they do not use."
(อย่าทำให้คลาสต้องพึ่งพาเมธอดที่มันไม่ได้ใช้)
❌ ตัวอย่างที่ไม่ดี:
interface Worker {
public function work();
public function eat();
}
class Robot implements Worker {
public function work() {
return "ทำงาน!";
}
public function eat() {
throw new Exception("หุ่นยนต์ไม่กินข้าว!");
}
}
✅ วิธีแก้: แยก Interface
interface Workable {
public function work();
}
interface Eatable {
public function eat();
}
class Robot implements Workable {
public function work() {
return "ทำงาน!";
}
}
ข้อดีของ ISP:
- ลดการใช้ method ที่ไม่จำเป็น
- คลาสลูก implement interface เท่าที่จำเป็น
5. Dependency Inversion Principle (DIP) - แยกส่วนการพึ่งพาออกจากกัน
หลักการ:
"Depend on abstractions, not concretions."
(ควรพึ่งพา abstraction มากกว่าการอ้างอิงถึง class โดยตรง)
❌ ตัวอย่างที่ไม่ดี:
class MySQLDatabase {
public function connect() {
return "เชื่อมต่อ MySQL!";
}
}
class UserRepository {
private $db;
public function __construct() {
$this->db = new MySQLDatabase(); // ❌ ผูกกับ MySQL โดยตรง
}
}
✅ วิธีแก้: ใช้ Dependency Injection
interface Database {
public function connect();
}
class MySQLDatabase implements Database {
public function connect() {
return "เชื่อมต่อ MySQL!";
}
}
class UserRepository {
private $db;
public function __construct(Database $db) {
$this->db = $db;
}
}
ข้อดีของ DIP:
- เปลี่ยน Database ได้ง่าย
- ลดการพึ่งพาของ class
SOLID Principles ช่วยให้โค้ด PHP ของเรามีโครงสร้างที่ดีขึ้น แก้ไขและขยายโค้ดได้ง่าย ลดบั๊กที่อาจเกิดขึ้น ถ้าคุณต้องการเป็น PHP Developer ที่เก่งขึ้น SOLID เป็นแนวคิดที่คุณควรรู้!
ไม่มีความคิดเห็น:
แสดงความคิดเห็น