เมื่อเร็ว ๆ นี้คุณเจาะลึกถึงsingleton design patternวิธีการนำไปใช้ใน Java และมีไว้เพื่ออะไร แต่ถ้าฉันบอกคุณว่า Java มาพร้อมกับซิงเกิลตันของตัวเองเมื่อแกะกล่อง ทึ่ง? แล้วมาดำน้ำกัน

คุณอาจรู้เกี่ยวกับคลาส Enumแล้ว มีคุณสมบัติพิเศษที่คุณควรทราบ โดยเฉพาะอย่างยิ่งEnumใช้รูปแบบการออกแบบซิงเกิลตัน ตัวเลือกนี้เกือบจะเหมือนกับแนวทางซิงเกิลตันที่เกี่ยวข้องกับสนามสาธารณะ

Singleton เป็น enum:


public enum Device {   
    PRINTER	
} 
    

Singleton เป็นตัวแปรสาธารณะ:


public class Printer {   
    public static final Printer PRINTER = new Printer();   
    private Printer() {
    }
//…
}
    

แนวทางenumนั้นกะทัดรัดกว่าแนวทางสาธารณะ เนื่องจากเราไม่จำเป็นต้องเขียนการนำไปใช้เอง สิ่งสำคัญที่สุดคือ enums ไม่มีปัญหากับการทำให้เป็นอนุกรม

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

คุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับการสะท้อนกลับในบทเรียนในโมดูลที่สอง ซึ่งเราจะสำรวจReflection API

Java ห้ามการสร้างอินสแตนซ์ enums ซึ่งเป็นข้อจำกัดในการปรับใช้เมธอดnewInstanceของคลาสConstructorซึ่งมักถูกเรียกใช้เมื่อสร้างวัตถุผ่านการสะท้อนกลับ

ข้อความที่ตัดตอน มาของโค้ดจากConstructor.newInstance ใช้เพื่อสร้าง enum :


if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
    

ข้อเสียของการใช้ enum เพื่อสร้าง singleton ได้แก่ :

  • ขาดการเริ่มต้นที่ขี้เกียจ เนื่องจากวัตถุถูกสร้างขึ้นทันทีและการเริ่มต้นไม่สามารถล่าช้าได้

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

  • เมื่อใช้ enum เป็น singleton คุณสามารถใช้ฟิลด์enum ได้เพียงฟิลด์เดียวเท่านั้น


public enum Device extends Electricity { 
    PRINTER 
}
    

รหัสนี้จะทำให้เรามีข้อผิดพลาดในการรวบรวม:

ไม่อนุญาตให้ขยายประโยคสำหรับ enum

แต่ถ้าเราต้องการใช้อินเทอร์เฟซ ก็ไม่มีปัญหา เนื่องจากenumสามารถใช้อินเทอร์เฟซได้:


public enum Device implements Electricity { 
    PRINTER 
}
    

หากคุณไม่ต้องการใช้การสืบทอด วิธีที่ดีที่สุดคือใช้รูปแบบ singleton ผ่านenum เราไม่ได้แนะนำสิ่งนี้คนเดียว — Joshua Bloch เองก็ทำเช่นกัน

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