メインコンテンツへ移動

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

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

Singleton Pattern: สร้าง Object ได้เพียงตัวเดียว

บทความนี้อธิบายถึง Singleton Pattern ซึ่งเป็น Design Pattern ที่รับประกันว่า Class จะมี instance เพียงตัวเดียว และมีจุดเข้าถึงส่วนกลาง (global access point) เพื...

Singleton Pattern: สร้าง Object ได้เพียงตัวเดียว

ในบทที่แล้ว เราได้พูดถึง Design Patterns ในภาพรวม และได้เห็นตัวอย่างของ Creational, Structural, และ Behavioral patterns กันไปบ้างแล้ว ในบทนี้ เราจะเจาะลึกลงไปใน Creational pattern ที่ชื่อว่า Singleton Pattern ซึ่งเป็น pattern ที่มีประโยชน์ในการควบคุมการสร้าง Object ให้มีเพียงตัวเดียวในระบบ

Singleton Pattern คืออะไร?

Singleton Pattern คือ Design Pattern ที่รับประกันว่า Class จะมี instance (object) เพียงตัวเดียวเท่านั้น และมี global access point เพื่อให้ทุกส่วนของโค้ดสามารถเข้าถึง instance นั้นได้

ลองนึกภาพว่าคุณมี Class ที่จัดการการเชื่อมต่อกับฐานข้อมูล คุณต้องการให้ทั้งระบบใช้การเชื่อมต่อฐานข้อมูลเพียงชุดเดียว เพื่อประหยัดทรัพยากรและหลีกเลี่ยงปัญหาความไม่สอดคล้องกันของข้อมูล Singleton Pattern จะช่วยให้คุณมั่นใจได้ว่าจะมี Object ที่จัดการการเชื่อมต่อฐานข้อมูลเพียงตัวเดียวเท่านั้น

การ Implement Singleton Pattern ใน PHP

การ Implement Singleton Pattern ใน PHP มีขั้นตอนหลักๆ ดังนี้:

  1. ประกาศ Constructor ให้เป็น `private`: เพื่อป้องกันไม่ให้ใครก็ตามสร้าง instance ใหม่ของ Class โดยตรง
  2. สร้าง static method ที่ชื่อ `getInstance()`: Method นี้จะทำหน้าที่สร้าง instance ของ Class หากยังไม่มี หรือคืนค่า instance ที่มีอยู่แล้ว
  3. เก็บ instance ของ Class ไว้ใน static property: เพื่อให้สามารถเข้าถึง instance ที่ถูกสร้างไว้ก่อนหน้าได้

นี่คือตัวอย่างโค้ด:

class DatabaseConnection {
  private static $instance;
  private $connection;

  // Constructor ต้องเป็น private
  private function __construct() {
    // จำลองการเชื่อมต่อฐานข้อมูล
    $this->connection = new stdClass();
    $this->connection->status = "Connected to database";
    echo "Database connection established.\n";
  }

  // ป้องกันการ clone object
  private function __clone() {
    // do nothing
  }

  // ป้องกัน unserialize
  public function __wakeup() {
    throw new \Exception("Cannot unserialize singleton");
  }

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

    return self::$instance;
  }

  public function getConnectionStatus() {
    return $this->connection->status;
  }
}

// การใช้งาน
$db1 = DatabaseConnection::getInstance();
echo $db1->getConnectionStatus() . "\n";

$db2 = DatabaseConnection::getInstance();
echo $db2->getConnectionStatus() . "\n";

// ตรวจสอบว่า $db1 และ $db2 เป็น instance เดียวกัน
if ($db1 === $db2) {
  echo "Both variables point to the same instance.\n";
}

คำอธิบายโค้ด:

  • `private static $instance;`: Property นี้ใช้เก็บ instance ของ Class
  • `private function __construct()`: Constructor ถูกประกาศให้เป็น `private` เพื่อป้องกันการสร้าง instance โดยตรงจากภายนอก Class
  • `private function __clone()`: ป้องกันการ clone object เพื่อรักษาสถานะ singleton
  • `public function __wakeup()`: ป้องกันการ unserialize object เพื่อรักษาสถานะ singleton
  • `public static function getInstance()`: Method นี้จะตรวจสอบว่ามี instance อยู่แล้วหรือไม่ ถ้ายังไม่มีก็จะสร้าง instance ใหม่ แล้วเก็บไว้ใน `$instance` และคืนค่า instance นั้นกลับไป ถ้ามี instance อยู่แล้ว ก็จะคืนค่า instance ที่มีอยู่

เมื่อรันโค้ดนี้ คุณจะเห็นว่า Constructor ถูกเรียกเพียงครั้งเดียว และ `$db1` กับ `$db2` ชี้ไปยัง instance เดียวกัน

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

ข้อดี:

  • ควบคุมการสร้าง instance: รับประกันว่าจะมี instance เพียงตัวเดียวของ Class
  • Global access point: ทำให้ทุกส่วนของโค้ดสามารถเข้าถึง instance ได้ง่าย
  • ประหยัดทรัพยากร: หลีกเลี่ยงการสร้าง Object ที่ซ้ำซ้อน

ข้อเสีย:

  • Global state: Singleton ถือเป็น global state ซึ่งอาจทำให้โค้ดทดสอบได้ยากขึ้น และลดความยืดหยุ่นของโค้ด
  • Violation of Single Responsibility Principle: Class Singleton อาจมีหน้าที่มากกว่าหนึ่งอย่าง คือทั้งการจัดการ instance และการทำงานหลักของ Class เอง
  • Hidden dependencies: การใช้ Singleton อาจทำให้ dependencies ของ Class ไม่ชัดเจน ทำให้ยากต่อการเข้าใจและแก้ไขโค้ด

เมื่อไหร่ควรใช้ Singleton Pattern?

Singleton Pattern เหมาะสำหรับกรณีที่คุณต้องการ:

  • Object ที่มีเพียงตัวเดียวในระบบ เช่น การจัดการการเชื่อมต่อฐานข้อมูล, การจัดการ Configuration, หรือ Logger
  • Global access point ไปยัง Object นั้น
  • เลี่ยงการส่ง Object นั้นผ่าน Parameter หลายๆ ที่

อย่างไรก็ตาม ควรพิจารณาข้อเสียของ Singleton Pattern ก่อนตัดสินใจใช้งาน และอาจพิจารณาทางเลือกอื่น เช่น Dependency Injection (ที่เราจะพูดถึงในบทต่อๆ ไป) หาก Singleton Pattern ไม่เหมาะสมกับสถานการณ์นั้น

ทางเลือกอื่นแทน Singleton Pattern

เนื่องจากข้อเสียที่กล่าวมาข้างต้น ทำให้หลายครั้งการใช้ Singleton Pattern ถูกมองว่าเป็นการออกแบบที่ไม่ดีนัก (Anti-Pattern) ดังนั้น มาดูทางเลือกอื่นๆ ที่สามารถใช้แทน Singleton ได้:

  • Dependency Injection (DI): เป็นทางเลือกที่ได้รับความนิยมมากกว่า DI ช่วยให้เราสามารถส่ง Object ที่ต้องการใช้งานให้กับ Class ได้โดยตรง ทำให้ Class ไม่ต้องรับผิดชอบในการสร้าง Object เอง ซึ่งช่วยลด dependencies และทำให้โค้ดทดสอบได้ง่ายขึ้น
  • Static Factory Method: คล้ายกับ Singleton ตรงที่สามารถสร้าง Object ได้จาก Method static แต่ Static Factory Method สามารถสร้าง Object หลายแบบได้ ขึ้นอยู่กับ Parameter ที่ส่งเข้ามา

สรุป

Singleton Pattern เป็น Design Pattern ที่มีประโยชน์ในการควบคุมการสร้าง Object ให้มีเพียงตัวเดียวในระบบ แต่ก็มีข้อเสียที่ควรพิจารณา ก่อนตัดสินใจใช้งาน ควรพิจารณาทางเลือกอื่น เช่น Dependency Injection เพื่อให้โค้ดมีความยืดหยุ่นและทดสอบได้ง่ายขึ้น ในบทต่อไป เราจะมาเรียนรู้เกี่ยวกับ Factory Pattern ซึ่งเป็นอีกหนึ่ง Creational pattern ที่น่าสนใจ

Office.in.th Custom Service

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

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

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