제이온

[Effective Java] รายการที่ 3: รับประกัน Singleton ด้วยตัวสร้างส่วนตัวหรือประเภท enum

สร้าง: 2024-04-27

สร้าง: 2024-04-27 00:48

ซิงเกิลตัน

แนวคิดของซิงเกิลตัน

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


วิธีการสร้างซิงเกิลตัน

วิธีการใช้สมาชิก 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> ได้


หากไม่มีความจำเป็นที่จะต้องใช้ข้อดีข้างต้น แนะนำให้ใช้วิธีแรก


วิธีการใช้ enum


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

แต่ควรระมัดระวังว่าซิงเกิลตันที่ต้องการสร้างนั้นสามารถสืบทอดอินเทอร์เฟซได้ แต่ไม่สามารถสืบทอดคลาสได้


สิ่งที่ควรระวังเมื่อซีเรียลไลซ์คลาสซิงเกิลตัน

หากต้องการซีเรียลไลซ์คลาสซิงเกิลตันที่สร้างขึ้นโดยใช้วิธีแรกหรือวิธีที่สอง นอกจากการใช้อินเทอร์เฟซ Serializable แล้ว ยังต้องประกาศอินสแตนซ์ฟิลด์ทั้งหมดเป็น transient และเขียนทับ readResolve() method เพื่อให้สามารถใช้ได้



แหล่งที่มา

ความคิดเห็น0

การสร้างแบบจำลองข้อมูลเชิงแนวคิดการสร้างแบบจำลองข้อมูลเชิงแนวคิดเป็นกระบวนการที่ใช้ ERD ในการแสดงเอนทิตีและความสัมพันธ์ เพื่อเป็นพื้นฐานในการออกแบบฐานข้อมูล
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

April 8, 2024

เรื่องราวการพัฒนาโครงการ LegiNote ตอนที่ 4 - โฮมเน็ตเวิร์กโดยบังเอิญนี่คือโพสต์บล็อกของ StatPan ที่กล่าวถึงการสร้างเซิร์ฟเวอร์โครงการย่อย LegiNote โดยใช้โฮมเน็ตเวิร์กส่วนตัว แบ่งปันกระบวนการสร้างเซิร์ฟเวอร์โดยใช้ Oracle Cloud Free Tier และมินิพีซี รวมถึงประสบการณ์การตั้งค่าโฮมเน็ตเวิร์กในสภาพแวดล้อมอินเทอร์เน็ตของ SK
statpan
statpan
statpan
statpan

October 19, 2024

สร้างเฟรมเวิร์กระดับ DI ด้วย Node.js แม้จะเป็นมือใหม่บทความนี้จะอธิบายวิธีการใช้การอัดฉีดการพึ่งพา (DI) ในการพัฒนาเซิร์ฟเวอร์ Node.js โดยใช้ฟังก์ชัน Reflect Metadata ของคอมไพเลอร์ TypeScript ในการใช้ DI และแนะนำไลบรารีที่เกี่ยวข้อง
Sunrabbit
Sunrabbit
Sunrabbit
Sunrabbit

November 8, 2024

การใช้ช่องหลักใน Slack อย่างมีประสิทธิภาพ: วิธีการจัดการช่องประกาศอย่างมีประสิทธิผลเราจะมาแนะนำวิธีการใช้ช่องที่ไม่สามารถลบได้ใน Slack เป็นช่องประกาศอย่างมีประสิทธิภาพ รวมถึงการตั้งค่าสิทธิ์ผู้ดูแลระบบและวิธีการใช้ฟังก์ชัน @mention
꿈많은청년들
꿈많은청년들
꿈많은청년들
꿈많은청년들

October 22, 2024

[สำหรับผู้ไม่ใช่ผู้เชี่ยวชาญ ด้านการพัฒนาซอฟต์แวร์ เพื่อความอยู่รอด] 14. สรุปเนื้อหาสัมภาษณ์ทางเทคนิคที่ผู้พัฒนาซอฟต์แวร์มือใหม่ถามบ่อยสรุปคำถามทางเทคนิคที่มักถามในการสัมภาษณ์งานผู้พัฒนาซอฟต์แวร์มือใหม่ (พื้นที่หน่วยความจำ โครงสร้างข้อมูล ฐานข้อมูล ฯลฯ) หวังว่าจะเป็นประโยชน์ในการเตรียมตัวสัมภาษณ์งานด้านการพัฒนา
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

April 3, 2024