ซิงเกิลตัน
แนวคิดของซิงเกิลตัน
ซิงเกิลตันหมายถึงคลาสที่สามารถสร้างอินสแตนซ์ได้เพียงหนึ่งเดียวเท่านั้น ตัวอย่างทั่วไปของซิงเกิลตัน ได้แก่ ออบเจกต์ที่ไม่มีสถานะ หรือคอมโพเนนต์ระบบที่ไม่ซ้ำกัน อย่างไรก็ตาม คลาสซิงเกิลตันนั้นทดสอบได้ยาก หากไม่ได้กำหนดชนิดเป็นอินเทอร์เฟซและกำหนดเป็นการนำไปใช้งาน
วิธีการสร้างซิงเกิลตัน
วิธีการใช้สมาชิก static ที่เป็น final field
คอนสตรัคเตอร์แบบ private จะถูกเรียกใช้เพียงครั้งเดียวเมื่อเริ่มต้นอินสแตนซ์ Elvis และรับประกันว่าเป็นอินสแตนซ์เดียวในระบบทั้งหมด อย่างไรก็ตาม สามารถใช้ AccessibleObject.setAccessible() เพื่อเรียกใช้คอนสตรัคเตอร์แบบ private ได้ ซึ่งวิธีการปรับเปลี่ยนโดยใช้ Reflection นี้สามารถป้องกันได้โดยการสร้างข้อยกเว้นเมื่อสร้างออบเจกต์ที่ 2
- ข้อดี
- API แสดงให้เห็นอย่างชัดเจนว่าคลาสนี้เป็นซิงเกิลตัน
- เรียบง่าย
วิธีการให้ static factory method แบบ public static
วิธีการนี้ก็รับประกันได้ว่าเป็นอินสแตนซ์เดียวในระบบทั้งหมด ยกเว้นการปรับเปลี่ยนผ่าน Reflection เพียงแค่เปลี่ยนฟิลด์เป็น private และใช้วิธีการ static factory method ในการส่งคืนออบเจกต์
- ข้อดี
- สามารถเปลี่ยนเป็นไม่ใช่ซิงเกิลตันได้โดยไม่ต้องเปลี่ยน API
- ตัวอย่างเช่น สามารถส่งคืนอินสแตนซ์ที่แตกต่างกันสำหรับแต่ละเธรดที่เรียกใช้ static factory method ได้
- สามารถเปลี่ยนเป็น generic singleton factory method ได้หากต้องการ
- สามารถใช้ method reference ของ static factory เป็น supplier ได้
- ตัวอย่างเช่น สามารถใช้ Elvis::getInstance แทน Supplier<Elvis> ได้
- สามารถเปลี่ยนเป็นไม่ใช่ซิงเกิลตันได้โดยไม่ต้องเปลี่ยน API
หากไม่มีความจำเป็นที่จะต้องใช้ข้อดีข้างต้น แนะนำให้ใช้วิธีแรก
วิธีการใช้ enum
วิธีที่ดีที่สุดคือการใช้อินเทอร์เฟซแบบ enum วิธีนี้ปลอดภัยกว่าการโจมตีด้วย Reflection และโค้ดก็ดูสะอาดตาขึ้น นอกจากนี้ ดังที่ได้กล่าวไว้ข้างต้น วิธีทั้งสองวิธีข้างต้นมีข้อเสียคือต้องเพิ่มโค้ดเพิ่มเติมเมื่อทำการซีเรียลไลซ์
แต่ควรระมัดระวังว่าซิงเกิลตันที่ต้องการสร้างนั้นสามารถสืบทอดอินเทอร์เฟซได้ แต่ไม่สามารถสืบทอดคลาสได้
สิ่งที่ควรระวังเมื่อซีเรียลไลซ์คลาสซิงเกิลตัน
หากต้องการซีเรียลไลซ์คลาสซิงเกิลตันที่สร้างขึ้นโดยใช้วิธีแรกหรือวิธีที่สอง นอกจากการใช้อินเทอร์เฟซ Serializable แล้ว ยังต้องประกาศอินสแตนซ์ฟิลด์ทั้งหมดเป็น transient และเขียนทับ readResolve() method เพื่อให้สามารถใช้ได้
ความคิดเห็น0