![translation](https://cdn.durumis.com/common/trans.png)
นี่คือโพสต์ที่แปลด้วย AI
[Effective Java] รายการที่ 3: รับประกัน Singleton ด้วยคอนสตรัคเตอร์ส่วนตัวหรือไดเร็กทอรี
- ภาษาที่เขียน: ภาษาเกาหลี
- •
-
ประเทศอ้างอิง: ทุกประเทศ
- •
- เทคโนโลยีสารสนเทศ
เลือกภาษา
สรุปโดย AI ของ durumis
- Singleton คือคลาสที่สามารถสร้างอินสแตนซ์ได้เพียงหนึ่งเดียว และใช้สำหรับ สร้างวัตถุที่ไม่มีสถานะหรือส่วนประกอบของระบบที่ไม่ซ้ำกัน
- วิธีการสร้าง Singleton ได้แก่ วิธีการที่สมาชิก public static เป็นฟิลด์แบบ final วิธีการที่ให้เมธอดแบบคงที่ และวิธีการที่ใช้ประเภทการแจกแจง โดยวิธีการที่ใช้ ประเภทการแจกแจงเป็นวิธีที่เหมาะสมที่สุด
- เมื่อลำดับคลาส Singleton คุณต้องใช้อินเทอร์เฟซ Serializable และประกาศฟิลด์อินสแตนซ์ ทั้งหมดเป็น transient และเขียนทับเมธอด readResolve()
ซิงเกิลตัน
แนวคิดของซิงเกิลตัน
ซิงเกิลตันหมายถึงคลาสที่สามารถสร้างอินสแตนซ์ได้เพียงหนึ่งเดียวเท่านั้น ตัวอย่างทั่วไปของซิงเกิลตัน ได้แก่ อ็อบเจ็กต์ที่ไม่มีสถานะหรือส่วนประกอบของระบบที่ไม่ซ้ำกัน อย่างไรก็ตาม คลาสซิงเกิลตันนั้นยากต่อการทดสอบ เว้นแต่จะกำหนดชนิดเป็นอินเทอร์เฟซและกำหนดเป็นการนำไปใช้
วิธีการสร้างซิงเกิลตัน
วิธีการใช้สมาชิก static ที่เป็น final field
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public void speak() {
System.out.println("elvis");
}
คอนสตรัคเตอร์ส่วนตัวถูกเรียกใช้เพียงครั้งเดียวเมื่อเริ่มต้นอินสแตนซ์ของ Elvis และรับประกันว่าเป็นอินสแตนซ์เดียวในระบบทั้งหมด อย่างไรก็ตาม สามารถเรียกใช้คอนสตรัคเตอร์ส่วนตัวโดยใช้ AccessibleObject.setAccessible() ได้ วิธีการดัดแปลงโดยใช้รีเฟล็กชันนี้สามารถป้องกันได้โดยการโยนข้อยกเว้นเมื่อสร้างอ็อบเจ็กต์ที่สอง
- ข้อดี
- ชัดเจนว่าคลาสนั้นเป็นซิงเกิลตันใน API
- กระชับ
วิธีการมอบหมาย static factory method เป็น public static
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public static Elvis getInstance() {
return INSTANCE;
}
public void speak() {
System.out.println("elvis");
}
วิธีนี้ยังรับประกันว่าเป็นอินสแตนซ์เดียวในระบบทั้งหมด ยกเว้นการดัดแปลงโดยใช้รีเฟล็กชัน แค่เปลี่ยนฟิลด์เป็น private และใช้วิธีการ static factory method ในการส่งคืนอ็อบเจ็กต์
- ข้อดี
- สามารถเปลี่ยนแปลงเป็น non-singleton ได้โดยไม่ต้องเปลี่ยนแปลง API
- ตัวอย่างเช่น ส่งคืนอินสแตนซ์ที่แตกต่างกันสำหรับแต่ละเธรดที่เรียกใช้ static factory method
- สามารถเปลี่ยนเป็น generic singleton factory method ได้หากต้องการ
- สามารถใช้การอ้างอิงวิธีการของ static factory เป็น supplier
- ตัวอย่างเช่น สามารถใช้ Elvis::getInstance เป็น Supplier<Elvis> ได้
- สามารถเปลี่ยนแปลงเป็น non-singleton ได้โดยไม่ต้องเปลี่ยนแปลง API
หากไม่มีโอกาสใช้ข้อดีข้างต้น ควรใช้วิธีการแรก
วิธีการใช้ enum
public enum Elvis {
INSTANCE;
public void speak() {
System.out.println("elvis");
}
วิธีที่ดีที่สุดคือการใช้ enum วิธีนี้ปลอดภัยกว่าการโจมตีโดยใช้รีเฟล็กชันและรหัสก็เรียบร้อยกว่าด้วย นอกจากนี้ ดังที่กล่าวไว้ด้านล่าง วิธีการทั้งสองข้างต้นมีข้อเสียคือต้องเพิ่มรหัสเพิ่มเติมเมื่อทำการซีเรียลไลซ์
แต่ควรระวังว่าซิงเกิลตันที่จะสร้างนั้นสามารถสืบทอดอินเทอร์เฟซได้ แต่ไม่สามารถสืบทอดคลาสได้
สิ่งที่ควรระวังเมื่อซีเรียลไลซ์คลาสซิงเกิลตัน
หากต้องการซีเรียลไลซ์คลาสซิงเกิลตันที่สร้างโดยใช้วิธีการแรกหรือที่สอง คุณจะต้องประกาศทุกฟิลด์เป็น transient นอกเหนือจากการนำไปใช้ Serializable และกำหนด readResolve() method ใหม่
private Object readResolve throws ObjectStreamException {
return INSTANCE;