9.2 การใช้ Design Patterns ที่นิยม เช่น Singleton, Factory, Observer
9.2 การใช้ Design Patterns ที่นิยม เช่น Singleton, Factory, Observer
การใช้ Design Patterns ในการออกแบบโปรแกรมขนาดใหญ่ เป็นวิธีการที่ช่วยให้โปรแกรมมีความยืดหยุ่น อ่านง่าย และรองรับการเปลี่ยนแปลงได้ดี Design Patterns เหล่านี้เป็นการจัดรูปแบบการแก้ปัญหาในการเขียนโค้ด โดยมีการออกแบบที่ได้รับการยอมรับและพิสูจน์แล้วว่าทำงานได้อย่างมีประสิทธิภาพในหลาย ๆ สถานการณ์
ในบรรดา Design Patterns ที่นิยมใช้นั้นมี 3 รูปแบบที่พบได้บ่อยในโปรแกรมขนาดใหญ่ ได้แก่ Singleton, Factory, และ Observer ซึ่งแต่ละแบบมีลักษณะการทำงานและประโยชน์เฉพาะตัว ดังนี้:
Singleton Pattern เป็นการออกแบบโครงสร้างที่ทำให้อ็อบเจกต์ของคลาสหนึ่ง ๆ ถูกสร้างขึ้นมาเพียงครั้งเดียวในโปรแกรม (single instance) เพื่อให้แน่ใจว่ามีเพียงอ็อบเจกต์เดียวที่ใช้ทรัพยากรบางอย่างร่วมกัน เช่น การเชื่อมต่อกับฐานข้อมูล, การเข้าถึงไฟล์ หรือค่าคงที่ที่ใช้ในระบบ
การใช้งาน Singleton Pattern
Singleton มักใช้ในสถานการณ์ที่จำเป็นต้องมีเพียงอ็อบเจกต์เดียว เช่น การบันทึกข้อมูลแบบ log, การเข้าถึงฐานข้อมูล หรือการใช้ global configuration เพื่อไม่ให้เกิดปัญหาความไม่สอดคล้องกันเมื่อหลายอ็อบเจกต์พยายามเข้าถึงหรือแก้ไขทรัพยากรเดียวกัน
ตัวอย่างการใช้งาน Singleton ในภาษา C++
#include <iostream>
using namespace std;
class Database {
private:
static Database* instance; // ชี้ไปยัง instance เพียงหนึ่งเดียวของคลาส
Database() {} // Constructor ต้องเป็น private
public:
static Database* getInstance() {
if (instance == nullptr) {
instance = new Database();
}
return instance;
}
void connect() {
cout << "Connected to the database." << endl;
}
};
Database* Database::instance = nullptr;
int main() {
Database* db1 = Database::getInstance();
Database* db2 = Database::getInstance();
db1->connect();
db2->connect();
// ตรวจสอบว่า db1 และ db2 เป็น instance เดียวกัน
if (db1 == db2) {
cout << "Both instances are the same." << endl;
}
return 0;
}
ในตัวอย่างนี้:
Database มีคอนสตรัคเตอร์ที่เป็น private ทำให้ไม่สามารถสร้างอ็อบเจกต์ Database ได้โดยตรงจากภายนอก
มีเมธอด getInstance() ที่สร้างอ็อบเจกต์ใหม่หากยังไม่มีอ็อบเจกต์นั้นและคืนค่าอ็อบเจกต์เดียวกันเสมอ เพื่อให้มั่นใจว่าจะมีเพียงอ็อบเจกต์เดียวที่ถูกสร้างขึ้น
ข้อดีของ Singleton คือช่วยควบคุมการเข้าถึงทรัพยากรที่มีจำกัด เช่น การเชื่อมต่อฐานข้อมูล ทำให้การจัดการทรัพยากรมีประสิทธิภาพมากขึ้น
Factory Pattern เป็นการออกแบบที่ช่วยสร้างอ็อบเจกต์โดยไม่จำเป็นต้องระบุคลาสของอ็อบเจกต์ที่ต้องการสร้างแบบเจาะจง โดยจะมีคลาส Factory ที่ทำหน้าที่สร้างอ็อบเจกต์ให้ตรงตามชนิดที่เราต้องการ ซึ่งเป็นการลดการพึ่งพาโค้ดและทำให้การขยายโปรแกรมทำได้ง่ายขึ้น
การใช้งาน Factory Pattern
Factory Pattern มักใช้ในกรณีที่ต้องการสร้างอ็อบเจกต์หลายชนิดที่มีอินเทอร์เฟซเดียวกัน เช่น ระบบการจ่ายเงินที่ต้องสร้างอ็อบเจกต์แบบ CreditCardPayment หรือ PaypalPayment ตามประเภทของการชำระเงินที่ผู้ใช้งานเลือก
ตัวอย่างการใช้งาน Factory ในภาษา C++
#include <iostream>
#include <string>
using namespace std;
class Payment {
public:
virtual void pay(int amount) = 0;
};
class CreditCardPayment : public Payment {
public:
void pay(int amount) override {
cout << "Paid " << amount << " using Credit Card." << endl;
}
};
class PaypalPayment : public Payment {
public:
void pay(int amount) override {
cout << "Paid " << amount << " using Paypal." << endl;
}
};
class PaymentFactory {
public:
static Payment* createPayment(const string& type) {
if (type == "CreditCard") {
return new CreditCardPayment();
} else if (type == "Paypal") {
return new PaypalPayment();
}
return nullptr;
}
};
int main() {
Payment* payment = PaymentFactory::createPayment("Paypal");
if (payment != nullptr) {
payment->pay(100);
delete payment;
}
payment = PaymentFactory::createPayment("CreditCard");
if (payment != nullptr) {
payment->pay(200);
delete payment;
}
return 0;
}
ในตัวอย่างนี้:
Payment เป็นคลาสพื้นฐาน (base class) ที่มีเมธอด pay() เป็น virtual function
CreditCardPayment และ PaypalPayment เป็นคลาสย่อยที่สืบทอดจาก Payment โดยต่างกันในพฤติกรรมของเมธอด pay()
PaymentFactory เป็นคลาส Factory ที่ใช้สร้างอ็อบเจกต์ Payment ตามชนิดที่ระบุ
ข้อดีของ Factory Pattern คือทำให้เราสามารถสร้างอ็อบเจกต์ได้โดยไม่ต้องรู้รายละเอียดของคลาสย่อย และยังช่วยให้โค้ดมีความยืดหยุ่นมากขึ้นเมื่อมีการเพิ่มชนิดของการจ่ายเงินใหม่
Observer Pattern เป็นรูปแบบการออกแบบที่ใช้ในสถานการณ์ที่มีหลายอ็อบเจกต์ (Observers) ต้องการทราบถึงการเปลี่ยนแปลงสถานะของอ็อบเจกต์ใดอ็อบเจกต์หนึ่ง (Subject) เมื่อมีการเปลี่ยนแปลงเกิดขึ้น Subject จะส่งการแจ้งเตือน (notification) ไปยัง Observers ทุกตัวที่ได้ลงทะเบียนไว้ วิธีนี้ช่วยให้เกิดการอัปเดตแบบเรียลไทม์ในหลาย ๆ ส่วนของโปรแกรมพร้อม ๆ กัน
การใช้งาน Observer Pattern
Observer Pattern มักใช้ในระบบที่ต้องการแสดงผลข้อมูลที่เปลี่ยนแปลงอยู่เสมอ เช่น ระบบที่แสดงผลราคาหุ้นหรือการแจ้งเตือนข้อความใหม่ ระบบดังกล่าวจะมีหลายส่วนที่ต้องอัปเดตตามข้อมูลที่เปลี่ยนแปลงไป
ตัวอย่างการใช้งาน Observer ในภาษา C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Observer {
public:
virtual void update(const string& message) = 0;
};
class Subject {
private:
vector<Observer*> observers;
public:
void addObserver(Observer* observer) {
observers.push_back(observer);
}
void removeObserver(Observer* observer) {
observers.erase(remove(observers.begin(), observers.end(), observer), observers.end());
}
void notify(const string& message) {
for (Observer* observer : observers) {
observer->update(message);
}
}
};
class ConcreteObserver : public Observer {
private:
string name;
public:
ConcreteObserver(const string& name) : name(name) {}
void update(const string& message) override {
cout << "Observer " << name << " received message: " << message << endl;
}
};
int main() {
Subject subject;
ConcreteObserver observer1("Observer1"), observer2("Observer2");
subject.addObserver(&observer1);
subject.addObserver(&observer2);
subject.notify("Stock prices updated!");
subject.removeObserver(&observer1);
subject.notify("New stock alert!");
return 0;
}
ในตัวอย่างนี้:
Observer เป็นคลาสพื้นฐานที่มีฟังก์ชัน update() ซึ่งจะถูกเรียกเมื่อมีการแจ้งเตือนจาก Subject
ConcreteObserver เป็นคลาสย่อยที่รับการแจ้งเตือนและพิมพ์ข้อความออกทางหน้าจอ
Subject ทำหน้าที่เป็นผู้ส่งการแจ้งเตือนไปยัง Observers ที่ได้ลงทะเบียนไว้
ข้อดีของ Observer Pattern คือทำให้เราสามารถออกแบบระบบที่มีการทำงานแบบเรียลไทม์ โดยที่ Subject และ Observers สามารถทำงานแยกกันได้อย่างอิสระ ทำให้การเปลี่ยนแปลงของข้อมูลถูกส่งไปยังหลาย ๆ ส่วนพร้อมกันได้
Singleton Pattern: ควบคุมการสร้างอ็อบเจกต์เพียงตัวเดียวเพื่อใช้ร่วมกันในโปรแกรม ช่วยลดการใช้ทรัพยากรอย่างมีประสิทธิภาพ
Factory Pattern: ช่วยสร้างอ็อบเจกต์โดยไม่ต้องเจาะจงชนิดคลาส ลดการพึ่งพาโค้ด
อ่านบทความเพิ่มเติมเกี่ยวกับ รูปแบบการออกแบบใน Java: Singleton, Factory และBuilder