เหตุใดจึงใช้ซิงเกิลตันแทนวิธีการคงที่


94

ฉันไม่เคยพบคำตอบที่ดีสำหรับคำถามง่ายๆเหล่านี้เกี่ยวกับคลาสตัวช่วย / ยูทิลิตี้:

เหตุใดฉันจึงต้องสร้างซิงเกิลตัน (ไร้สัญชาติ) แทนที่จะใช้วิธีการแบบคงที่

เหตุใดจึงจำเป็นต้องใช้อินสแตนซ์วัตถุหากวัตถุไม่มีสถานะ


สำเนาที่เป็นไปได้ของstackoverflow.com/questions/720744/static-class-and-singleton
Michael Borgwardt

อย่าคิดว่าเราพูดถึง 2 ภาษาที่แตกต่างกันดังนั้นคำตอบอาจแตกต่างกันไป แต่ขอบคุณสำหรับลิงค์ใน java ไม่เคยได้ยินคำว่า "monostate"
Sebastien Lorber

คำตอบ:


79

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

อย่างไรก็ตามมีบางกรณีที่แม้แต่คนโสดไร้สัญชาติก็มีประโยชน์:

  • คุณคาดว่าจะขยายไปพร้อมกับสถานะในอนาคตอันใกล้
  • คุณต้องมีอินสแตนซ์ออบเจ็กต์ด้วยเหตุผลทางเทคนิคบางประการ
    ตัวอย่าง: อ็อบเจ็กต์การซิงโครไนซ์สำหรับ C # lockหรือsynchronizedคำสั่งJava
  • คุณต้องการการสืบทอดกล่าวคือคุณต้องการที่จะสามารถแทนที่ซิงเกิลตันของคุณด้วยอีกอันหนึ่งได้อย่างง่ายดายโดยใช้อินเทอร์เฟซเดียวกัน แต่ใช้งานต่างกัน
    ตัวอย่าง: Toolkit.getDefaultToolkit()เมธอดใน Java จะส่งคืน Singleton ที่มีประเภทที่แน่นอนขึ้นอยู่กับระบบ
  • คุณต้องการความเสมอภาคอ้างอิงสำหรับค่าแมวมอง
    ตัวอย่าง: DBNull.Valueใน C #

27
ฉันจะใช้ +1 แม้ว่าเสื้อกล้าม IMHO จะถูกนำไปใช้ในทางที่ผิดเพื่อแนะนำรัฐทั่วโลก จุดประสงค์ของซิงเกิลตันไม่ใช่เพื่อทำให้อ็อบเจกต์พร้อมใช้งานทั่วโลก แต่เพื่อบังคับให้อ็อบเจ็กต์ถูกสร้างอินสแตนซ์เพียงครั้งเดียว วัตถุระดับโลกเป็นสิ่งชั่วร้ายที่จำเป็น หากไม่จำเป็นจริงๆควรพยายามอย่าใช้เนื่องจากโดยทั่วไปแล้วจะทำให้เกิดการมีเพศสัมพันธ์สูงโดยมี SomeSingleton.getInstance (). someMethod () อยู่ทั่วทุกที่ :)
back2dos

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

2
ส่วน "เปลี่ยนซิงเกิลตันของคุณได้อย่างง่ายดาย" เป็นจุดที่สำคัญที่สุดในมุมมองของฉัน ส่วนที่เหลือค่อนข้างใกล้เคียงกับการใช้คลาสแบบคงที่
Teoman shipahi

1
Singletons เป็นค่า Sentinel ที่ไม่เป็นค่าว่างที่มีประโยชน์สำหรับผลรวม / ประเภทผลิตภัณฑ์และที่คล้ายกัน ตัวอย่างเช่นเป็นค่าไม่มี / ไม่มีอะไรในประเภทตัวเลือกหรือค่าว่างสำหรับประเภทคอลเลกชัน คุณจะได้รับการทดสอบที่รวดเร็วไม่มี / ว่างเปล่าเป็นโบนัสเพราะความเท่าเทียมกันในการอ้างอิงเป็นสิ่งที่จำเป็น
itsbruce

@itsbruce: ตัวอย่างของคุณไม่ใช่singletons : รายการว่างไม่ใช่อินสแตนซ์เดียวที่เป็นไปได้ของคลาส List และค่า None ไม่ใช่อินสแตนซ์เดียวที่เป็นไปได้ของคลาส Option อย่างไรก็ตามมีตัวอย่างที่ค่า sentinel เป็น singletons และฉันได้ใช้เสรีภาพในการเพิ่มคำตอบของฉัน ขอบคุณสำหรับอินพุท!
Heinzi

37

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

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

การทำให้เป็นอินสแตนซ์ซิงเกิลตันช่วยให้มั่นใจได้ว่าคุณไม่ได้จัดสรรอ็อบเจ็กต์ประเภทใดมากเกินความจำเป็น (เนื่องจากคุณต้องการเพียงอย่างเดียว)


1
"คุณไม่สามารถควบคุมได้ว่าใครสามารถใช้งานได้หรือที่ไหน" ทำไมใครบางคนถึงต้องการมัน?
hagrawal

1
@hagrawal เพื่อจุดประสงค์ในการทดสอบคุณควรจะล้อเลียนได้
Jemshit Iskenderov

15

อันที่จริงฉันพบคำตอบอื่นที่ไม่ได้กล่าวถึงที่นี่: วิธีการแบบคงที่ทดสอบได้ยากกว่า

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


2
แต่ดูเหมือนว่า Powermock จะทำได้
Sebastien Lorber

6

ในชั้นเรียนภาษาโปรแกรมส่วนใหญ่จะหลีกเลี่ยงระบบประเภทต่างๆมากมาย ในขณะที่คลาสที่มีเมธอดแบบคงที่และตัวแปรเป็นอ็อบเจ็กต์ แต่บ่อยครั้งที่ไม่สามารถใช้อินเทอร์เฟซหรือขยายคลาสอื่น ๆ ได้ ด้วยเหตุนี้จึงไม่สามารถใช้ในลักษณะที่หลากหลายได้เนื่องจากไม่สามารถเป็นชนิดย่อยของประเภทอื่นได้ ตัวอย่างเช่นหากคุณมีอินเทอร์เฟซIFooableซึ่งจำเป็นต้องใช้โดยลายเซ็นหลายวิธีของคลาสอื่นStaticFooไม่สามารถใช้อ็อบเจ็กต์คลาสแทนได้ในIFooableขณะที่FooSingleton.getInstance()สามารถ (สมมติว่าFooSingletonใช้IFooable)

โปรดทราบว่าขณะที่ฉันแสดงความคิดเห็นเกี่ยวกับคำตอบของ Heinzi ซิงเกิลตันเป็นรูปแบบในการควบคุมการสร้างอินสแตนซ์ แทนที่new Class()ด้วยClass.getInstance()ซึ่งทำให้ผู้เขียนClassสามารถควบคุมอินสแตนซ์ได้มากขึ้นซึ่งเขาสามารถใช้เพื่อป้องกันการสร้างอินสแตนซ์ที่ไม่จำเป็น ซิงเกิลตันเป็นเพียงกรณีพิเศษของรูปแบบโรงงานและควรได้รับการปฏิบัติเช่นนี้ การใช้งานทั่วไปทำให้เป็นกรณีพิเศษของการลงทะเบียนทั่วโลกซึ่งมักจะลงเอยด้วยความไม่ดีเนื่องจากไม่ควรใช้การลงทะเบียนทั่วโลกเพียงแค่ตั้งใจ

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

Greetz
back2dos


4

มีการแลกเปลี่ยนระหว่างการใช้อันไหน Singletons อาจมีหรือไม่มีสถานะและอ้างถึงวัตถุ หากไม่ได้รักษาสถานะและใช้สำหรับการเข้าถึงทั่วโลกเท่านั้นแบบคงที่จะดีกว่าเนื่องจากวิธีการเหล่านี้จะเร็วขึ้น แต่ถ้าคุณต้องการใช้ประโยชน์จากวัตถุและแนวคิด OOP (ความหลากหลายทางมรดก) แล้วซิงเกิลตันจะดีกว่า

ลองพิจารณาตัวอย่าง: java.lang.Runtime เป็นคลาส singleton ใน java คลาสนี้อนุญาตให้นำไปใช้งานที่แตกต่างกันสำหรับแต่ละ JVM การใช้งานเป็นแบบเดี่ยวต่อ JVM หากคลาสนี้เป็นแบบคงที่เราจะไม่สามารถส่งผ่านการใช้งานที่แตกต่างกันตาม JVM

ฉันพบว่าลิงค์นี้มีประโยชน์จริงๆ: http://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html ?

หวังว่าจะช่วย !!


คำตอบนี้เหมาะสำหรับการรวมตัวอย่างที่เป็นรูปธรรมในโลกแห่งความเป็นจริง
systemovich

2

สำหรับฉัน"ต้องการสถานะวัตถุใช้ Singleton ต้องการฟังก์ชันใช้วิธีคงที่"

มันขึ้นอยู่กับสิ่งที่คุณต้องการ เมื่อใดก็ตามที่คุณต้องการสถานะของวัตถุ (เช่นความหลากหลายเช่นสถานะ Null แทนnullหรือสถานะเริ่มต้น) singleton เป็นตัวเลือกที่เหมาะสมสำหรับคุณในขณะที่วิธีการแบบคงที่จะใช้เมื่อคุณต้องการฟังก์ชัน (รับอินพุตแล้วส่งคืนเอาต์พุต)

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

ปล. ประสิทธิภาพระหว่าง 2 ตัวนี้ต่างกันเป็นมิลลิวินาทีดังนั้นควรเน้นที่สถาปัตยกรรมก่อน


1

Singleton ไม่ได้เป็นคนไร้สัญชาติ แต่ถือเป็นรัฐระดับโลก

เหตุผลบางประการที่ฉันคิดได้ในการใช้ Singleton ได้แก่ :

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

ฉันรู้ แต่จริงๆแล้วคนโสดสามารถเป็นคนไร้สัญชาติได้ไม่มากก็น้อย ... ถ้ามันไม่แบ่งปันคุณสมบัติของคลาสใด ๆ ...
Sebastien Lorber
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.