รูปแบบการสร้างสรรค์: Singleton

Dec 04 2022
บทความนี้อธิบายถึงวิธีที่รูปแบบ Singleton บังคับใช้เพียงอินสแตนซ์เดียวของคลาสที่เคยสร้างและมีอยู่ตลอดอายุการใช้งานของแอปพลิเคชัน มันคืออะไร? singleton เป็นรูปแบบการออกแบบที่ใช้สร้างอินสแตนซ์ของคลาสเดียว

บทความนี้อธิบายถึงวิธีที่รูปแบบ Singleton บังคับใช้เพียงอินสแตนซ์เดียวของคลาสที่เคยสร้างและมีอยู่ตลอดอายุการใช้งานของแอปพลิเคชัน

มันคืออะไร?

singleton เป็นรูปแบบการออกแบบที่ใช้สร้างอินสแตนซ์ของคลาสเดียว โดยทั่วไปจะใช้รูปแบบ Singleton เมื่อมีหลายตัวอย่างที่ควรมีอยู่เพียงอินสแตนซ์เดียวของคลาสและมีการบังคับใช้ข้อจำกัด ตัวอย่างเช่น แคช เธรดพูล และรีจิสตรีควรมีเพียงอินสแตนซ์เดียว

ทำให้ตัวสร้างเป็นส่วนตัวเพื่อให้แน่ใจว่ามีการสร้างวัตถุคลาสเดียวเท่านั้น ด้วยวิธีนี้ เฉพาะสมาชิกชั้นเรียนเท่านั้นที่สามารถเข้าถึงตัวสร้างส่วนตัวและไม่มีใครอื่น

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

แผนภาพคลาส

แผนภาพชั้นเรียนประกอบด้วยเอนทิตีเดียวเท่านั้น

ซิงเกิลตัน

ตัวอย่าง

สมมติว่าเราต้องการจำลองเครื่องบินอย่างเป็นทางการของประธานาธิบดีอเมริกันที่ชื่อ Airforce One ในซอฟต์แวร์ของเรา คลาส Singleton เป็นตัวแทนที่เหมาะสมที่สุดสำหรับเอนทิตีที่มีเพียงอินสแตนซ์เดียว

นี่คือรหัสสำหรับคลาสซิงเกิลตันของเรา:

มัลติเธรดและซิงเกิลตัน

รหัสนี้ใช้งานได้ตราบเท่าที่แอปพลิเคชันเป็นแบบเธรดเดียว อย่างไรก็ตาม หากเธรดจำนวนมากเข้าถึงคลาสนี้ มีความเป็นไปได้ที่วัตถุต่างๆ จะถูกสร้างขึ้น

ตัวอย่างเช่น:

  • เธรด A เรียกใช้เมธอดgetInstanceและค้นหาonlyInstanceค่าเป็นโมฆะ อย่างไรก็ตาม ก่อนที่มันจะสามารถสร้างอินสแตนซ์ได้ บริบทจะถูกเปลี่ยนออกไป
  • ตอนนี้เธรด B มาพร้อมและเรียกgetInstanceซึ่งส่งคืนAirforceOneวัตถุ
  • หากมีกำหนดการเธรด A อีกครั้ง ความเสียหายจะเริ่มต้นขึ้น เธรดผ่านการตรวจสอบเงื่อนไข if-null แล้ว และจะดำเนินการสร้างAirforceOneวัตถุใหม่และกำหนดให้onlyInstanceกับ ตอนนี้มีAirforceOneวัตถุสองอย่างที่แตกต่างกันอยู่ในธรรมชาติ อันหนึ่งมีเธรด A และอีกอันมีเธรด B
  • ด้วยการเพิ่มsynchronizedวิธีgetInstance()การนี้ คุณจะได้ความปลอดภัยของเธรด
  • อีกทางเลือกหนึ่งคือการเริ่มต้นอินสแตนซ์แบบสแตติก การรับประกันว่าจะปลอดภัยต่อเธรด

ตรวจสอบการล็อคสองครั้ง

มีปัญหาสำคัญสองประการเกี่ยวกับวิธีการที่อธิบายไว้ข้างต้น: การซิงโครไนซ์มีราคาแพง และการเริ่มต้นแบบสแตติกจะสร้างออบเจกต์แม้ว่าจะไม่ได้ใช้ในการเรียกใช้แอปพลิเคชันเฉพาะก็ตาม หากการสร้างอ็อบเจกต์มีราคาแพง การกำหนดค่าเริ่มต้นแบบสแตติกอาจทำให้เราสูญเสียประสิทธิภาพการทำงาน

โซลูชันข้างต้นทำเครื่องหมายว่าอินสแตนซ์ซิงเกิลตันมีความผันผวน อย่างไรก็ตาม การปฏิบัติตามระเบียบวิธีของ JVM นี้volatileจะทำงานไม่ถูกต้องสำหรับการล็อกแบบตรวจสอบซ้ำ และคุณจะต้องใช้วิธีอื่นเพื่อสร้างซิงเกิลตันของคุณ

สำนวน การล็อคแบบ ตรวจสอบซ้ำตอนนี้ถือเป็น antipattern และยูทิลิตี้ของมันได้หายไปเนื่องจากเวลาเริ่มต้น JVM เร็วขึ้น

ตัวอย่างอื่นๆ

Java API ให้ singletons ต่อไปนี้แก่เรา:

java.lang.รันไทม์

java.awt.Desktop

คำเตือน

คุณสามารถ subclass คลาส singleton ได้โดยการปกป้องตัวสร้างแทนที่จะเป็นแบบส่วนตัว อย่างไรก็ตาม มีตัวเลือกที่ดีกว่านี้ในทุกสถานการณ์ ในสถานการณ์เหล่านี้ นักพัฒนาสามารถสร้างรีจีสทรีซิงเกิลตันสำหรับคลาสย่อยทั้งหมดได้ เมธอด getInstance สามารถใช้พารามิเตอร์หรือใช้ตัวแปรสภาพแวดล้อมเพื่อส่งคืนออบเจกต์ singleton ที่ต้องการ รีจิสทรีรักษาการแมปชื่อสตริงกับวัตถุซิงเกิล

บทความอื่นๆ ในชุด รูปแบบสร้างสรรค์