เกี่ยวกับรูปแบบการออกแบบ: เมื่อใดที่ฉันควรใช้ซิงเกิลตัน


448

ตัวแปรระดับโลกที่ได้รับเกียรติ - กลายเป็นระดับโลกที่รุ่งโรจน์ บางคนบอกว่าการออกแบบเชิงวัตถุแตก

ให้ฉันสถานการณ์อื่น ๆ นอกเหนือจากคนตัดไม้เก่าที่ดีที่มันเหมาะสมที่จะใช้ซิงเกิล


4
ตั้งแต่การเรียนรู้ภาษา erlang ฉันชอบวิธีการนี้นั่นคือการเปลี่ยนแปลงไม่ได้และการส่งข้อความ
Setori

209
ไม่มีอะไรที่สร้างสรรค์เกี่ยวกับคำถามนี้ ฉันเห็นคำตอบที่สร้างสรรค์ด้านล่าง
mk12

3
เฟรมเวิร์กการฉีดแบบพึ่งพาอาศัยเป็นซิงเกิลตันที่ซับซ้อนมากที่แจกออบเจ็กต์….
Ian Ringrose

1
Singleton สามารถใช้เป็นวัตถุผู้จัดการระหว่างอินสแตนซ์ของวัตถุอื่นดังนั้นจึงควรมีเพียงหนึ่งอินสแตนซ์ของ singleton ที่แต่ละอินสแตนซ์อื่นควรสื่อสารผ่านอินสแตนซ์ซิงเกิล
Levent Divilioglu

ฉันมีคำถามด้าน: การใช้งาน Singleton ใด ๆ ยังสามารถใช้งานได้โดยใช้คลาส "คงที่" (ด้วยวิธี "โรงงาน" / "init") - โดยไม่ต้องสร้างอินสแตนซ์ของชั้นเรียนจริง (คุณสามารถพูดได้ว่า การใช้งานแบบ Singleton แต่ ... ) - เหตุใดจึงควรใช้ Singleton จริง (อินสแตนซ์คลาสเดียวที่ทำให้แน่ใจว่าเป็นแบบเดี่ยว) แทนที่จะเป็นคลาสแบบสแตติก เหตุผลเดียวที่ฉันคิดได้อาจจะเป็น "ซีแมนทิกส์" แต่ในแง่นี้ซิงเกิลใช้งานก็ไม่ต้องการความสัมพันธ์แบบ "คลาส -> อินสแตนซ์" ตามคำจำกัดความ ... ดังนั้น ... ทำไม?
Yuval A.

คำตอบ:


358

ในการสืบเสาะหาความจริงฉันค้นพบว่าจริงๆแล้วมีเหตุผล "ยอมรับ" น้อยมากที่ใช้ซิงเกิลตัน

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

การบันทึกเป็นตัวอย่างเฉพาะของซิงเกิล "ยอมรับ" เนื่องจากไม่มีผลต่อการเรียกใช้โค้ดของคุณ ปิดใช้งานการบันทึกรหัสการใช้งานจะยังคงเหมือนเดิม เปิดใช้งานเหมือนกัน Misko วางไว้ในวิธีต่อไปนี้ในRoot Cause ของ Singletons "ข้อมูลที่นี่ไหลทางเดียว: จากแอปพลิเคชันของคุณไปที่ logger แม้ว่า loggers จะเป็นสถานะโกลบอลเนื่องจากไม่มีข้อมูลไหลจาก loggers ลงในแอพพลิเคชัน

ฉันแน่ใจว่ามีเหตุผลที่ถูกต้องอื่น ๆ เช่นกัน อเล็กซ์มิลเลอร์ใน " Patterns I Hate " พูดถึงผู้ให้บริการและ UI ฝั่งลูกค้าก็อาจเป็นตัวเลือก "ยอมรับได้"

อ่านเพิ่มเติมที่ Singleton ฉันรักคุณ แต่คุณกำลังทำให้ฉันผิดหวัง


3
@ ArneMertz ฉันคิดว่านี่เป็นหนึ่ง
Attacktive

1
ทำไมคุณไม่สามารถใช้วัตถุทั่วโลกได้? ทำไมต้องเป็นซิงเกิล?
รองเท้า

1
ฉันคิดว่าวิธีคงที่สำหรับการเข้าสู่ระบบ util?
Skynet

1
Singletons จะดีที่สุดเมื่อคุณต้องการจัดการทรัพยากร ตัวอย่างเช่นการเชื่อมต่อ Http คุณไม่ต้องการสร้างไคลเอนต์ http 1 ล้านตัวให้กับไคลเอนต์เดียวนั่นมันบ้าสิ้นเปลืองและช้า ดังนั้นซิงเกิลที่เชื่อมต่อกับไคลเอนต์ http pooled จะเร็วขึ้นและเป็นมิตรกับทรัพยากร
Cogman

3
ฉันรู้ว่านี่เป็นคำถามเก่าและข้อมูลในคำตอบนี้ดีมาก อย่างไรก็ตามฉันมีปัญหาในการทำความเข้าใจว่าทำไมคำตอบนี้จึงเป็นที่ยอมรับเมื่อ OP ระบุไว้อย่างชัดเจนว่า: "ให้ฉันสถานการณ์อื่น ๆ นอกเหนือจากคนตัดไม้เก่าที่ดีที่มันเหมาะสมที่จะใช้ซิงเกิล"
Francisco C.

124

ผู้สมัคร Singleton จะต้องตอบสนองความต้องการที่สาม:

  • ควบคุมการเข้าถึงพร้อมกันไปยังทรัพยากรที่ใช้ร่วมกัน
  • การเข้าถึงทรัพยากรจะได้รับการร้องขอจากหลาย ๆ ส่วนที่แตกต่างกันของระบบ
  • อาจมีเพียงวัตถุเดียวเท่านั้น

หากซิงเกิลที่เสนอของคุณมีข้อกำหนดเพียงหนึ่งหรือสองข้อการออกแบบใหม่มักเป็นตัวเลือกที่ถูกต้อง

ตัวอย่างเช่นตัวจัดคิวเครื่องพิมพ์ไม่น่าจะถูกเรียกจากที่เดียว (เมนูพิมพ์) ดังนั้นคุณสามารถใช้ mutexes เพื่อแก้ปัญหาการเข้าถึงพร้อมกัน

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


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

15
ฉันคิดว่าคุณพลาดคำว่า "ผู้สมัคร" ผู้สมัคร Singleton จะต้องปฏิบัติตามข้อกำหนดสามประการ เพียงเพราะสิ่งที่ตรงตามข้อกำหนดไม่ได้หมายความว่าควรเป็นซิงเกิลตัน อาจมีปัจจัยการออกแบบอื่น ๆ :)
metao

45

การอ่านไฟล์การกำหนดค่าที่ควรอ่านได้ในเวลาที่เริ่มต้นและการห่อหุ้มพวกเขาใน Singleton


8
คล้ายกับProperties.Settings.Defaultใน. NET
Nick Bedford

9
@Paul, "no-singleton camp" จะระบุว่าวัตถุการกำหนดค่าควรถูกส่งไปยังฟังก์ชั่นที่ต้องการแทนที่จะทำให้สามารถเข้าถึงได้ทั่วโลก (aka singleton)
Pacerier

2
ไม่เห็นด้วย หากการกำหนดค่าถูกย้ายไปยังฐานข้อมูลทุกอย่างจะเมา หากเส้นทางไปสู่การกำหนดค่านั้นขึ้นอยู่กับสิ่งใดก็ตามที่อยู่นอกซิงเกิลนั้นสิ่งเหล่านี้จำเป็นต้องคงที่เช่นกัน
rr-

3
@ PaulCroarkin คุณช่วยขยายเรื่องนี้และอธิบายว่าสิ่งนี้มีประโยชน์อย่างไร?
AlexG

1
@ rr- หากการกำหนดค่าย้ายไปยังฐานข้อมูลก็ยังสามารถถูกห่อหุ้มในวัตถุการกำหนดค่าซึ่งจะถูกส่งผ่านไปยังฟังก์ชั่นที่จำเป็น (PS ฉันไม่ได้อยู่ในค่าย "no-singleton")
Sheppard Will

36

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

หรือการเชื่อมต่อฐานข้อมูลหรือตัวจัดการไฟล์เป็นต้น


30
ฉันเคยได้ยินตัวอย่างตัวจัดคิวเครื่องพิมพ์นี้และฉันคิดว่ามันเป็นประเภทง่อย ใครบอกว่าฉันไม่มีสพูลเลอร์มากกว่าหนึ่งตัว อะไรคือตัวจัดคิวเครื่องพิมพ์อีกต่อไป ถ้าฉันมีเครื่องพิมพ์ประเภทต่าง ๆ ที่ไม่สามารถขัดแย้งหรือใช้ไดรเวอร์อื่นได้
1800 ข้อมูล

6
มันเป็นเพียงตัวอย่าง ... สำหรับทุกสถานการณ์ที่ทุกคนใช้เป็นตัวอย่างคุณจะสามารถค้นหาการออกแบบทางเลือกที่ทำให้ตัวอย่างนั้นไร้ประโยชน์ สมมติว่าตัวจัดคิวจัดการทรัพยากรเดียวที่ใช้ร่วมกันโดยหลายองค์ประกอบ มันได้ผล.
Vincent Ramdhanie

2
มันเป็นตัวอย่างคลาสสิกสำหรับ Gang of Four ฉันคิดว่าคำตอบที่มีกรณีทดลองใช้จริงจะมีประโยชน์มากกว่า ฉันหมายถึงสถานการณ์ที่คุณรู้สึกว่าซิงเกิลตันเป็นทางออกที่ดีที่สุด
Andrei Vajna II

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

ตัวจัดคิวเครื่องพิมพ์คืออะไร
RayLoveless

23

อ่านซิงเกิลตันเดียวที่เก็บสถานะโกลบอลบางอย่าง (ภาษาผู้ใช้, วิธีใช้ไฟล์พา ธ , เส้นทางแอปพลิเคชัน) นั้นสมเหตุสมผล ระมัดระวังการใช้ซิงเกิลตันเพื่อควบคุมตรรกะทางธุรกิจ - ซิงเกิลเกือบจะกลายเป็นหลาย ๆ


4
ภาษาผู้ใช้สามารถเป็นแบบซิงเกิลตันโดยมีข้อสันนิษฐานว่าผู้ใช้เพียงคนเดียวเท่านั้นที่สามารถใช้ระบบได้
ซามูเอลÅslund

…และผู้ใช้รายหนึ่งพูดเพียงภาษาเดียว
สเปกตรัม

17

การจัดการการเชื่อมต่อ (หรือกลุ่มของการเชื่อมต่อ) ไปยังฐานข้อมูล

ฉันจะใช้มันเพื่อดึงและจัดเก็บข้อมูลในไฟล์การกำหนดค่าภายนอก


2
เครื่องมือสร้างการเชื่อมต่อฐานข้อมูลจะไม่เป็นตัวอย่างของโรงงานหรือไม่
Ken

3
@Ken คุณต้องการให้โรงงานนั้นเป็นซิงเกิลตันในเกือบทุกกรณี
Chris Marisic

2
@Federico, "no-singleton camp" จะระบุว่าการเชื่อมต่อฐานข้อมูลเหล่านี้ควรจะถูกส่งผ่านไปยังฟังก์ชั่นที่ต้องการแทนที่จะทำให้พวกมันสามารถเข้าถึงได้ทั่วโลก (aka singleton)
Pacerier

3
คุณไม่ต้องการซิงเกิลตันสำหรับเรื่องนี้ มันสามารถฉีด
Nestor Ledon

11

หนึ่งในวิธีที่คุณใช้ซิงเกิลตันคือครอบคลุมอินสแตนซ์ที่จะต้องมี "นายหน้า" ควบคุมการเข้าถึงทรัพยากร Singletons มีความสามารถในการบันทึกที่ดีเพราะนายหน้าเข้าถึงไฟล์ซึ่งสามารถเขียนได้เฉพาะ สำหรับสิ่งที่ต้องการเข้าสู่ระบบพวกเขาให้วิธีการเขียนไปยังสิ่งที่เป็นนามธรรมเช่นไฟล์บันทึก - คุณสามารถห่อกลไกการแคชไว้ในซิงเกิลของคุณ ฯลฯ ...

ลองนึกถึงสถานการณ์ที่คุณมีแอพพลิเคชั่นที่มี windows / threads / etc จำนวนมาก แต่ต้องการการสื่อสารเพียงจุดเดียว ฉันเคยใช้งานหนึ่งงานเพื่อควบคุมงานที่ฉันต้องการให้แอปพลิเคชันเปิดตัว ซิงเกิลมีหน้าที่รับผิดชอบในการจัดอันดับงานและแสดงสถานะของพวกเขาไปยังส่วนอื่น ๆ ของโปรแกรมที่สนใจ ในสถานการณ์แบบนี้คุณสามารถดูซิงเกิลตันเหมือนกับคลาส "เซิร์ฟเวอร์" ที่กำลังทำงานอยู่ภายในแอปพลิเคชันของคุณ ... HTH


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

10

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

เมื่อใช้ Singletons คุณควรตรวจสอบให้แน่ใจว่าคุณไม่ได้ปกปิดการพึ่งพาโดยบังเอิญ ในอุดมคติแล้วจะมีการตั้งค่า singletons (เช่นตัวแปรสแตติกส่วนใหญ่ในแอปพลิเคชัน) ในระหว่างการประมวลผลรหัสเริ่มต้นสำหรับแอปพลิเคชัน (Static void Main () สำหรับ C # executables, void main main) สำหรับ java executables คลาสอื่นทั้งหมดที่อินสแตนซ์ที่ต้องการ สิ่งนี้จะช่วยให้คุณรักษาการทดสอบได้


8

ฉันคิดว่าการใช้งานแบบเดี่ยวสามารถนึกถึงความสัมพันธ์แบบหนึ่งต่อหนึ่งในฐานข้อมูล หากคุณมีส่วนต่าง ๆ ของรหัสของคุณที่ต้องทำงานกับอินสแตนซ์เดียวของวัตถุนั่นคือที่ที่เหมาะสมที่จะใช้ singletons


6

ตัวอย่างการใช้งานจริงของ singleton สามารถพบได้ในTest :: Builderคลาสที่สนับสนุนโมดูลการทดสอบ Perl สมัยใหม่ทุกรุ่น Test :: Builder ซิงเกิลตันจัดเก็บและโบรกเกอร์สถานะและประวัติของกระบวนการทดสอบ (ผลการทดสอบในอดีตนับจำนวนการทดสอบที่เรียกใช้) รวมถึงสิ่งต่าง ๆ ที่กำลังจะเกิดขึ้นของการทดสอบ สิ่งเหล่านี้เป็นสิ่งจำเป็นในการประสานงานโมดูลทดสอบหลายชุดซึ่งเขียนโดยผู้เขียนหลายคนเพื่อทำงานร่วมกันในสคริปต์ทดสอบเดียว

ประวัติความเป็นมาของการทดสอบ :: ตัวสร้างของซิงเกิลตันคือการศึกษา การโทรnew()จะให้วัตถุเดียวกันกับคุณเสมอ ก่อนอื่นข้อมูลทั้งหมดจะถูกเก็บไว้เป็นตัวแปรคลาสโดยไม่มีสิ่งใดในวัตถุนั้น สิ่งนี้ใช้ได้จนกระทั่งฉันต้องการทดสอบ Test :: Builder ด้วยตัวเอง จากนั้นฉันต้องการวัตถุ Test :: Builder สองตัวซึ่งหนึ่งการตั้งค่าเป็นดัมมี่เพื่อจับและทดสอบพฤติกรรมและผลลัพธ์ของมันและอีกอันหนึ่งเป็นวัตถุทดสอบจริง ณ จุดนั้น Test :: Builder ได้รับการ refactored เป็นวัตถุจริง วัตถุเดี่ยวถูกเก็บไว้เป็นข้อมูลระดับและnew()จะกลับมันเสมอ create()ถูกเพิ่มเข้ามาเพื่อสร้างวัตถุใหม่และเปิดใช้งานการทดสอบ

ขณะนี้ผู้ใช้ต้องการเปลี่ยนพฤติกรรมบางอย่างของ Test :: Builder ในโมดูลของตนเอง แต่ปล่อยให้อยู่คนเดียวในขณะที่ประวัติการทดสอบยังคงเหมือนกันในทุกโมดูลการทดสอบ สิ่งที่เกิดขึ้นตอนนี้คือการทดสอบเสาหิน :: ตัวสร้างวัตถุจะถูกแบ่งย่อยเป็นชิ้นเล็ก ๆ (ประวัติ, เอาต์พุต, รูปแบบ ... ) ด้วยอินสแตนซ์ของ Test :: Builder ที่รวบรวมพวกมันเข้าด้วยกัน ตอนนี้ทดสอบ :: ตัวสร้างไม่จำเป็นต้องเป็นซิงเกิลอีกต่อไป ส่วนประกอบเช่นประวัติสามารถเป็นได้ สิ่งนี้ทำให้ความจำเป็นที่ไม่ยืดหยุ่นของซิงเกิลตันลดลง ให้ความยืดหยุ่นแก่ผู้ใช้ในการผสมและจับคู่ชิ้นส่วน ตอนนี้วัตถุเดี่ยวขนาดเล็กสามารถเก็บข้อมูลได้โดยมีวัตถุที่มีการตัดสินใจว่าจะใช้งานอย่างไร นอกจากนี้ยังช่วยให้คลาสที่ไม่ใช่ Test :: Builder สามารถเล่นได้โดยใช้ประวัติ Test :: Builder และเอาท์พุทซิงเกิล

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


5

เมื่อคุณโหลดอ็อบเจ็กต์ Properties configuration จากฐานข้อมูลหรือไฟล์มันจะช่วยให้มันเป็น singleton; ไม่มีเหตุผลที่จะต้องอ่านข้อมูลคงที่ที่จะไม่เปลี่ยนแปลงในขณะที่เซิร์ฟเวอร์กำลังทำงานอยู่


2
ทำไมคุณไม่เพียงแค่โหลดข้อมูลเพียงครั้งเดียวแล้วส่งวัตถุการกำหนดค่าตามต้องการ
lagweezle

อะไรคือสิ่งที่ผ่านไป ??? ถ้าฉันต้องผ่านวัตถุทุกอย่างที่ฉันต้องการฉันจะมีตัวสร้าง 20 อาร์กิวเมนต์ ...
Enerccio

@Eccccio หากคุณมีวัตถุที่ต้องพึ่งพาคนอื่น 20 คนโดยไม่มีการห่อหุ้มคุณมีปัญหาการออกแบบที่สำคัญอยู่แล้ว
สเปกตรัม

@spectras ฉัน หากฉันใช้งานไดอะล็อก gui ฉันจะต้อง: ที่เก็บการแปลข้อมูลเซสชันข้อมูลแอปพลิเคชันวิดเจ็ตพาเรนต์ไคลเอ็นต์ข้อมูลผู้จัดการการอนุญาตและอาจมากกว่า แน่นอนว่าคุณสามารถรวมบางส่วนได้ แต่ทำไม โดยส่วนตัวแล้วฉันใช้สปริงและลักษณะต่าง ๆ ในการแสดงการพึ่งพาทั้งหมดเหล่านี้ลงในคลาสวิดเจ็ตและจะแยกทุกอย่างออก
Enerccio

หากคุณมีสถานะที่มากคุณสามารถพิจารณาใช้ซุ้มให้มุมมองที่เกี่ยวข้องกับบริบทเฉพาะ ทำไม? เพราะมันจะช่วยให้การออกแบบที่สะอาดโดยไม่ต้องมีตัวสร้าง antipatterns แบบซิงเกิลหรือ 29-arg ที่จริงแล้วกล่องโต้ตอบ Gui ของคุณเข้าถึงทุกสิ่งเหล่านั้นตะโกน "ละเมิดหลักการความรับผิดชอบเดียว"
สเปกตรัม

3

ตามที่ทุกคนกล่าวว่าทรัพยากรที่ใช้ร่วมกัน - โดยเฉพาะสิ่งที่ไม่สามารถจัดการการเข้าถึงพร้อมกัน

ตัวอย่างหนึ่งที่ฉันเห็นคือ Lucene Search Index Writer


1
และยัง IndexWriter ไม่ได้เป็นซิงเกิล ...
มาร์ค

3

คุณสามารถใช้ Singleton เมื่อใช้รูปแบบสถานะ (ในลักษณะที่แสดงในหนังสือ GoF) นี่เป็นเพราะคลาสรัฐที่เป็นรูปธรรมไม่มีสถานะของตนเองและดำเนินการในรูปแบบของคลาสบริบท

คุณสามารถทำให้ Abstract Factory กลายเป็นซิงเกิลตันได้


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

1
@ kiwicomb123 พยายามทำให้คุณมีsetState()ความรับผิดชอบในการตัดสินใจนโยบายการสร้างรัฐ ช่วยถ้าภาษาโปรแกรมของคุณรองรับเทมเพลตหรือยาชื่อสามัญ แทนที่จะใช้ Singleton คุณสามารถใช้รูปแบบMonostateโดยที่การสร้างอินสแตนซ์ของออบเจ็กต์สถานะกลายเป็นการใช้ซ้ำสถานะออบเจ็กต์โกลบอล / สแตติกเดียวกัน ไวยากรณ์สำหรับการเปลี่ยนสถานะอาจยังคงไม่เปลี่ยนแปลงเนื่องจากผู้ใช้ของคุณไม่จำเป็นต้องทราบว่าสถานะอินสแตนซ์เป็น Monostate
Emile Cormier

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

@ kiwicomb123 ไม่ได้ Monostate ไม่ได้เกี่ยวกับการทำให้สมาชิกทุกคนคงที่ ดีกว่าที่คุณอ่านมันแล้วตรวจสอบดังนั้นสำหรับคำถามและคำตอบที่เกี่ยวข้อง
Emile Cormier

ฉันรู้สึกว่าควรได้รับคะแนนเสียงมากกว่านี้ บทคัดย่อเป็นเรื่องธรรมดามากพอและเนื่องจากโรงงานไร้สัญชาติมีความเสถียรในการไร้สัญชาติและไม่สามารถนำไปใช้กับวิธีการคงที่ (ใน Java) ซึ่งไม่ overriden การใช้ singleton ควรจะไม่เป็นไร
DPM

3

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

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

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

$gb->config['hostname']

หรือมีค่าภาษาทั้งหมดในอาร์เรย์เช่น:

$gb->lang['ENTER_USER']

ในตอนท้ายของการเรียกใช้รหัสสำหรับหน้าคุณจะได้รับการพูดว่าเป็นผู้ใหญ่ตอนนี้:

$template

Singleton เป็น$gbsingleton ที่มีอาร์เรย์ lang สำหรับแทนที่และเอาต์พุตทั้งหมดถูกโหลดและพร้อมใช้งาน คุณเพียงแทนที่พวกเขาเป็นคีย์ที่มีอยู่ในค่าเพจของเทมเพลตวัตถุผู้ใหญ่และจากนั้นให้บริการแก่ผู้ใช้

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


21
คุณอาจต้องการแบ่งคำตอบออกเป็นหลายย่อหน้าและป้องกันส่วนรหัสเพื่อให้อ่านง่าย
Justin

1

มันอาจเป็นประโยชน์มากในการกำหนดค่าความกังวลโครงสร้างพื้นฐานที่เฉพาะเจาะจงเป็น singletons หรือตัวแปรทั่วโลก ตัวอย่างที่ฉันชอบคือ Dependency Injection framework ที่ใช้ singletons เพื่อทำหน้าที่เป็นจุดเชื่อมต่อกับเฟรมเวิร์ก

ในกรณีนี้คุณกำลังพึ่งพาโครงสร้างพื้นฐานเพื่อลดความซับซ้อนในการใช้ไลบรารีและหลีกเลี่ยงความซับซ้อนที่ไม่จำเป็น


0

ฉันใช้มันสำหรับวัตถุที่ห่อหุ้มพารามิเตอร์บรรทัดคำสั่งเมื่อจัดการกับโมดูลที่เสียบได้ โปรแกรมหลักไม่ทราบว่าพารามิเตอร์บรรทัดคำสั่งสำหรับโมดูลที่โหลด (และไม่เคยรู้ว่าโมดูลกำลังโหลดอยู่) เช่นโหลดหลัก A ซึ่งไม่ต้องการพารามิเตอร์ใด ๆ (ดังนั้นทำไมจึงควรใช้ตัวชี้ / อ้างอิง / อะไรก็ตามฉันไม่แน่ใจ - ดูเหมือนมลพิษ) จากนั้นโหลดโมดูล X, Y และ Z ของสิ่งเหล่านี้พูดพารามิเตอร์ X และ Z ต้องการ (หรือยอมรับ) ดังนั้นพวกเขาจึงโทรกลับไปที่บรรทัดคำสั่งซิงเกิลเพื่อบอกว่าพารามิเตอร์ใดที่ต้องยอมรับและรันไทม์ที่พวกเขาโทรกลับเพื่อตรวจสอบว่าผู้ใช้ระบุจริงหรือไม่ ของพวกเขา.

ในหลาย ๆ วิธีซิงเกิลตันสำหรับการจัดการพารามิเตอร์ CGI จะทำงานคล้ายกันถ้าคุณใช้เพียงหนึ่งกระบวนการต่อการสืบค้น (เมธอด mod_ * อื่น ๆ ไม่ได้ทำเช่นนี้ดังนั้นมันจะไม่ดีที่นั่น - ดังนั้นอาร์กิวเมนต์ที่บอกว่าคุณไม่ควร ' ไม่ใช้ซิงเกิลตันในโลก mod_cgi ในกรณีที่คุณพอร์ตไปยัง mod_perl หรืออะไรก็ตามในโลก)


-1

ตัวอย่างที่มีรหัสบางที

ที่นี่ ConcreteRegistry เป็นเกมซิงเกิลในโป๊กเกอร์ที่ช่วยให้พฤติกรรมทุกอย่างขึ้นไปบนผังแพ็กเกจเข้าถึงได้เพียงไม่กี่อินเตอร์เฟสหลักของเกม (เช่นด้านหน้าของแบบจำลองมุมมองตัวควบคุมสภาพแวดล้อม ฯลฯ ):

http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html

เอ็ด


1
ตอนนี้ลิงก์ใช้งานไม่ได้ แต่ถ้าคุณกำลังลงทะเบียนข้อมูลการดูในซิงเกิลตันซึ่งจะเข้าถึงได้ตลอดทั้งแอปพลิเคชันคุณจะพลาดจุด MVC มุมมองถูกอัพเดตโดย (และสื่อสารกับ) คอนโทรลเลอร์ซึ่งใช้โมเดล ฟังดูตรงนี้มันอาจเป็นการใช้ผิดวิธีของซิงเกิลตันและการรีแฟคเตอร์เป็นไปตามลำดับ
drharris

-9

1 - ความคิดเห็นเกี่ยวกับคำตอบแรก:

ฉันไม่เห็นด้วยกับคลาส Logger แบบคงที่ สิ่งนี้สามารถนำไปใช้ได้จริงสำหรับการนำไปใช้ แต่ไม่สามารถเปลี่ยนได้สำหรับการทดสอบหน่วย คลาสแบบคงที่ไม่สามารถแทนที่ด้วยการทดสอบสองครั้ง หากคุณไม่ทดสอบหน่วยคุณจะไม่เห็นปัญหาที่นี่

2 - ฉันพยายามไม่สร้างซิงเกิลตันด้วยมือ ฉันเพิ่งสร้างวัตถุอย่างง่ายพร้อมคอนสตรัคเตอร์ที่อนุญาตให้ฉันใส่ผู้ทำงานร่วมกันลงในวัตถุ ถ้าฉันต้องการซิงเกิลตันฉันจะใช้เฟรมเวิร์ก inyection (Spring.NET, Unity for .NET, Spring สำหรับ Java) หรืออื่น ๆ


11
คุณควรแสดงความคิดเห็นกับคำตอบโดยตรงโดยคลิกที่ลิงค์ด้านล่างของคำตอบ มันง่ายกว่ามากที่จะอ่านวิธีนี้ คำตอบที่คุณเห็นที่ด้านบนอาจไม่ใช่คำตอบแรก คำตอบจะได้รับการจัดลำดับใหม่ตลอดเวลา
Ross

ทำไมคุณต้องการบันทึกการทดสอบหน่วย
Enerccio

มีความแตกต่างอย่างมากระหว่าง "คลาส Logger แบบสแตติก" และอินสแตนซ์ Logger แบบสแตติกตัวอย่างรูปแบบซิงเกิลไม่ได้บอกว่า "ทำให้คลาสของคุณคงที่" มันบอกว่าให้เข้าถึงอินสแตนซ์ของวัตถุคงที่ ตัวอย่างเช่นILogger logger = Logger.SingleInstance();เมื่อวิธีนี้เป็นแบบสแตติกและส่งคืนอินสแตนซ์ที่เก็บไว้แบบคงที่ของ ILogger คุณใช้ตัวอย่างของ "กรอบงานการฉีดพึ่งพา" ภาชนะ DI เกือบทั้งหมดเป็นแบบซิงเกิล การกำหนดค่าของพวกเขาจะถูกกำหนดแบบคงที่และเข้าถึงได้จาก / เก็บไว้ในที่สุดในส่วนติดต่อผู้ให้บริการเดียว
Jon Davis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.