ทำไมรัฐโลกถึงชั่วร้าย?


328

ก่อนที่เราจะเริ่มสิ่งนี้ให้ฉันบอกว่าฉันตระหนักดีถึงแนวคิดของ Abstraction และ Dependency Injection ฉันไม่ต้องการตาที่เปิดอยู่ที่นี่

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

สมมติว่าฉันต้องการการกำหนดค่าทั่วโลกสำหรับแอปพลิเคชันของฉันเช่นเส้นทางของโฟลเดอร์ระบบหรือหนังสือรับรองฐานข้อมูลทั่วทั้งแอปพลิเคชัน

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

ฉันรู้ว่ามันไม่ดีที่จะละเมิดมัน แต่เป็นพื้นที่ทั่วโลกจริงๆที่ชั่ว? และถ้าเป็นเช่นนั้นมีทางเลือกอะไรที่ดีบ้าง?


5
คุณสามารถใช้คลาสการกำหนดค่าที่จัดการการเข้าถึงการตั้งค่าเหล่านั้น ฉันคิดว่ามันเป็นแนวปฏิบัติที่ดีที่จะมีหนึ่งเดียวที่เดียวเท่านั้นที่การตั้งค่าการอ่านจากไฟล์ config และ / หรือฐานข้อมูลในขณะที่วัตถุอื่นดึงพวกเขาจากสิ่ง config มันทำให้การออกแบบของคุณสะอาดและคาดเดาได้มากขึ้น
Hajo

25
ความแตกต่างกับการใช้ทั่วโลกอยู่ที่ไหน "สถานที่แห่งเดียวและแห่งเดียว" ของคุณฟังดูน่าสงสัยอย่าง Singleton
Madara Uchiha

130
ความชั่วร้ายที่แท้จริงเท่านั้นคือความประพฤติ
Pieter B

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

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

คำตอบ:


282

สั้นมากทำให้สถานะของโปรแกรมไม่แน่นอน

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

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

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

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

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

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

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

มีเหตุผลอื่น ๆ อีกมากมายที่ทำให้การผ่านรัฐรอบ ๆ นั้นเหนือกว่าการพึ่งพารัฐทั่วโลกอย่างมากมาย คำตอบนี้ไม่ครอบคลุม คุณอาจจะเขียนหนังสือทั้งเล่มเกี่ยวกับสาเหตุที่รัฐไม่ดี


61
โดยพื้นฐานแล้วเนื่องจากทุกคนสามารถเปลี่ยนสถานะได้คุณจึงไม่สามารถไว้ใจได้
Oded

21
@Truth ทางเลือกหรือไม่ พึ่งพาการฉีด
rdlowrey

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

53
ไม่มีสิ่งใดที่อธิบายว่าทำไมตัวแปรทั่วโลกแบบอ่านอย่างเดียวไม่ดี…ซึ่ง OP ได้ถามอย่างชัดเจน มันเป็นคำตอบที่ดีมากฉันแค่แปลกใจที่ OP ทำเครื่องหมายว่า "ยอมรับ" เมื่อเขาพูดถึงประเด็นที่แตกต่างอย่างชัดเจน
Konrad Rudolph

20
being able to unit test code is a major step in the process of proving its correctness (or at least fitness for purpose). ไม่มันไม่ใช่ "ขณะนี้เป็นเวลาสองทศวรรษแล้วตั้งแต่มีการชี้ให้เห็นว่าการทดสอบโปรแกรมอาจแสดงให้เห็นถึงการปรากฏตัวของข้อบกพร่อง แต่ไม่สามารถแสดงให้เห็นถึงข้อบกพร่องของพวกเขาได้หลังจากอ้างคำพูดที่ได้รับการเผยแพร่อย่างดีนี้ เพื่อปรับแต่งกลยุทธ์การทดสอบของเขาเช่นเดียวกับนักเล่นแร่แปรธาตุของสมัยก่อนซึ่งยังคงกลั่นกรองการสกัดคริสโซของเขาต่อไป " - Djikstra, 1988. (นั่นทำให้ 4.5 ทศวรรษแล้วตอนนี้ ... )
Mason Wheeler

135

สภาวะโลกที่เปลี่ยนแปลงไม่ได้เป็นสิ่งชั่วร้ายด้วยเหตุผลหลายประการ:

  • ข้อบกพร่องจากสถานะโลกที่เปลี่ยนแปลงไม่ได้ - ข้อบกพร่องจำนวนมากเกิดจากความไม่แน่นอน ข้อบกพร่องที่อาจเกิดจากการกลายพันธุ์จากที่ใดก็ได้ในโปรแกรมนั้นเป็นเรื่องที่หลอกลวงเนื่องจากมักจะยากที่จะติดตามสาเหตุที่แท้จริง
  • ความสามารถในการทดสอบต่ำ - ถ้าคุณมีสถานะโกลบอลที่ไม่แน่นอนคุณจะต้องกำหนดค่าสำหรับการทดสอบใด ๆ ที่คุณเขียน นี่ทำให้การทดสอบยากขึ้น (และคนที่เป็นคนจึงมีโอกาสน้อยที่จะทำ!) เช่นในกรณีของหนังสือรับรองฐานข้อมูลทั่วทั้งแอปพลิเคชันจะเกิดอะไรขึ้นถ้าการทดสอบหนึ่งครั้งจำเป็นต้องเข้าถึงฐานข้อมูลทดสอบเฉพาะที่แตกต่างจากทุกอย่าง?
  • ความยืดหยุ่น - จะเกิดอะไรขึ้นหากส่วนหนึ่งของรหัสต้องการค่าหนึ่งในสถานะส่วนกลาง แต่อีกส่วนหนึ่งต้องการค่าอื่น (เช่นค่าชั่วคราวระหว่างการทำธุรกรรม) ทันใดนั้นคุณมีสิ่งที่น่ารังเกียจในมือของคุณ
  • ความไม่บริสุทธิ์ของฟังก์ชั่น - ฟังก์ชั่น "บริสุทธิ์" (เช่นที่ผลลัพธ์ขึ้นอยู่กับพารามิเตอร์อินพุตและไม่มีผลข้างเคียง) จะง่ายกว่ามากในการให้เหตุผลและเขียนโปรแกรมเพื่อสร้างโปรแกรมขนาดใหญ่ ฟังก์ชันที่อ่านหรือควบคุมสถานะโกลบอลที่ไม่แน่นอนนั้นไม่บริสุทธิ์
  • ความเข้าใจโค้ด - พฤติกรรมของโค้ดที่ขึ้นอยู่กับตัวแปรโกลบอลที่ผันแปรได้จำนวนมากนั้นยากที่จะเข้าใจ - คุณต้องเข้าใจช่วงของการโต้ตอบที่เป็นไปได้กับตัวแปรโกลบอลก่อนที่คุณจะสามารถให้เหตุผลเกี่ยวกับพฤติกรรมของโค้ด ในบางสถานการณ์ปัญหานี้อาจกลายเป็นว่ายาก
  • ปัญหาการเกิดภาวะพร้อมกัน - โดยทั่วไปสถานะโกลบอลที่ไม่แน่นอนต้องใช้รูปแบบการล็อคบางอย่างเมื่อใช้ในสถานการณ์ที่เกิดขึ้นพร้อมกัน สิ่งนี้ยากที่จะทำให้ถูกต้อง (เป็นสาเหตุของข้อบกพร่อง) และเพิ่มความซับซ้อนให้กับโค้ดของคุณมากขึ้น (ยาก / แพงเกินไปที่จะรักษา)
  • ประสิทธิภาพ - เธรดหลายเธรดอย่างต่อเนื่องในสถานะโกลบอลเดียวกันทำให้เกิดการช่วงชิงแคชและจะทำให้ระบบของคุณช้าลงโดยรวม

ทางเลือกอื่น ๆ สำหรับสถานะโลกที่เปลี่ยนแปลงไม่ได้:

  • พารามิเตอร์ฟังก์ชั่น - มักถูกมองข้าม แต่การกำหนดพารามิเตอร์การทำงานของคุณให้ดีขึ้นนั้นมักจะเป็นวิธีที่ดีที่สุดในการหลีกเลี่ยงสถานะโกลบอล มันบังคับให้คุณแก้คำถามเชิงแนวคิดที่สำคัญ: ฟังก์ชั่นนี้ต้องการข้อมูลอะไรในการทำงาน บางครั้งมันก็สมเหตุสมผลที่จะมีโครงสร้างข้อมูลที่เรียกว่า "บริบท" ที่สามารถส่งต่อสายโซ่ของฟังก์ชันที่รวบรวมข้อมูลที่เกี่ยวข้องทั้งหมด
  • การพึ่งพาการฉีด - เช่นเดียวกับพารามิเตอร์ของฟังก์ชันเพิ่งทำไปก่อนหน้านี้เล็กน้อย (ที่การก่อสร้างวัตถุแทนที่จะเป็นการเรียกใช้ฟังก์ชัน) ระวังหากการอ้างอิงของคุณเป็นวัตถุที่ไม่แน่นอนแม้ว่าจะทำให้เกิดปัญหาเช่นเดียวกับสถานะโกลบอลที่ไม่แน่นอน .....
  • รัฐทั่วโลกที่ไม่เปลี่ยนรูปนั้นส่วนใหญ่ไม่เป็นอันตราย - เป็นค่าคงที่ได้อย่างมีประสิทธิภาพ แต่ให้แน่ใจว่ามันเป็นค่าคงที่จริงๆและคุณจะไม่ถูกล่อลวงให้เปลี่ยนเป็นสถานะโลกที่เปลี่ยนแปลงไม่ได้ในภายหลัง!
  • ซิงเกิลที่ไม่เปลี่ยนรูปแบบ - ค่อนข้างเหมือนกับรัฐโลกที่ไม่เปลี่ยนรูปยกเว้นว่าคุณสามารถเลื่อนการอินสแตนซ์ได้จนกว่าพวกเขาจะต้องการ มีประโยชน์สำหรับเช่นโครงสร้างข้อมูลขนาดใหญ่คงที่ที่ต้องใช้การคำนวณล่วงหน้าแบบราคาแพงครั้งเดียว ซิงเกิลที่ไม่แน่นอนเป็นแน่นอนเทียบเท่ากับรัฐโลกที่ไม่แน่นอนและเป็นสิ่งที่ชั่วร้าย :-)
  • การเชื่อมโยงแบบไดนามิก - ใช้ได้เฉพาะในบางภาษาเช่น Common Lisp / Clojure เท่านั้น แต่สิ่งนี้จะช่วยให้คุณผูกค่าภายในขอบเขตที่ควบคุมได้ ในระดับหนึ่งนี่เป็นวิธีที่ "ปลอดภัย" ในการรับผลเช่นเดียวกับตัวแปรกลางเนื่องจากคุณทราบว่าจะมีผลกระทบเฉพาะเธรดการเรียกใช้ปัจจุบันเท่านั้น สิ่งนี้มีประโยชน์โดยเฉพาะอย่างยิ่งในกรณีที่คุณมีหลายเธรดแต่ละรายการที่จัดการธุรกรรมอิสระเช่น

11
ฉันคิดว่าการส่งผ่านวัตถุบริบทโดยพารามิเตอร์ฟังก์ชั่นหรือการฉีดพึ่งพาจะทำให้เกิดปัญหาหากบริบทไม่แน่นอนปัญหาเช่นเดียวกับการใช้รัฐทั่วโลกที่ไม่แน่นอน
Alfredo Osorio

1
ทุกสิ่งที่ดีและสาธุ! แต่คำถามนี้เกี่ยวกับสถานะโลกที่เปลี่ยนแปลงไม่ได้
MarkJ

@Alfredo - จริงมาก แม้ว่ามันจะไม่ได้เป็นที่ไม่ดีเพราะอย่างน้อยขอบเขตที่สามารถควบคุมได้บ้าง แต่โดยทั่วไปแล้วมันง่ายกว่าที่จะแก้ปัญหาด้วยการสร้างบริบทและการพึ่งพาไม่เปลี่ยนรูป
mikera

2
+1 สำหรับการเปลี่ยนแปลงไม่ได้ / ไม่เปลี่ยนรูป ดาวทรงกลมที่ไม่เปลี่ยนรูปก็โอเค แม้แต่คนที่ขี้เกียจโหลด แต่ไม่เคยเปลี่ยน แน่นอนว่าอย่าเปิดเผยตัวแปรโกลบอล แต่เป็นอินเตอร์เฟสหรือ API ระดับโลก
Jess

1
@giorgio คำถามทำให้ชัดเจนว่าตัวแปรในคำถามรับค่าเมื่อเริ่มต้นและไม่เปลี่ยนแปลงหลังจากนั้นในระหว่างการดำเนินการโปรแกรม (โฟลเดอร์ระบบข้อมูลประจำตัวฐานข้อมูล) เช่นไม่เปลี่ยนรูปจะไม่เปลี่ยนแปลงเมื่อได้รับค่า ส่วนตัวแล้วฉันก็ใช้คำว่า "state" เพราะมันอาจแตกต่างจากการประมวลผลหนึ่งไปอีกการประมวลผลหนึ่งหรือเครื่องอื่น อาจมีคำพูดที่ดีกว่า
MarkJ

62
  1. เนื่องจากแอปทั้งหมดของคุณสามารถใช้งานได้มันจึงยากที่จะแยกแยะพวกมันออกมาอีกครั้งอย่างไม่น่าเชื่อ หากคุณเคยเปลี่ยนแปลงสิ่งที่ต้องทำกับโลกของคุณรหัสทั้งหมดของคุณต้องเปลี่ยน นี่คืออาการปวดหัวในการบำรุงรักษามากกว่าแค่grepชื่อประเภทเพื่อค้นหาว่าฟังก์ชันใดใช้งาน
  2. พวกเขาไม่ดีเพราะพวกเขาแนะนำการพึ่งพาที่ซ่อนอยู่ซึ่งทำลายการทำงานแบบมัลติเธรดซึ่งมีความสำคัญมากยิ่งขึ้นต่อแอพพลิเคชั่นจำนวนมาก
  3. สถานะของตัวแปรส่วนกลางนั้นไม่น่าเชื่อถืออย่างสมบูรณ์อยู่เสมอเพราะรหัสของคุณทั้งหมดสามารถทำอะไรกับมันได้
  4. มันยากที่จะทดสอบ
  5. พวกเขาเรียก API ยาก "คุณต้องจำไว้ว่าให้เรียก SET_MAGIC_VARIABLE () ก่อนที่จะโทรหา API" เป็นเพียงการขอร้องให้บางคนลืมที่จะโทรหา มันทำให้การใช้ข้อผิดพลาด API ได้ง่ายก่อให้เกิดข้อผิดพลาดที่หายาก ด้วยการใช้มันเป็นพารามิเตอร์ปกติคุณบังคับให้ผู้เรียกต้องระบุค่าอย่างเหมาะสม

เพียงส่งการอ้างอิงไปยังฟังก์ชันที่ต้องการ มันไม่ยากเลย


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

6
@Coder: โปรดทราบว่าทางเลือกที่มีเหตุผลสำหรับโกลบอลไม่ใช่ "ผู้อ่านการกำหนดค่าจากสถานที่ 1000x ในรหัส" แต่ผู้อ่านการกำหนดค่าหนึ่งซึ่งสร้างวัตถุการกำหนดค่าซึ่งวิธีการที่สามารถยอมรับเป็นพารามิเตอร์ (-> การพึ่งพาการพึ่งพา)
sleske

2
Nitpicking: ทำไมการพิมพ์ grep ถึงง่ายกว่าแบบโกลบอล และคำถามนั้นเกี่ยวกับ
วงกลมรอบ

2
@ MarkJ: ฉันหวังว่าไม่มีใครเคยพูดเงาชื่อ
DeadMG

2
@DeadMG, Re ".. มันไม่น่าเชื่อถืออย่างสมบูรณ์เสมอ .. " เหมือนกันสำหรับการขึ้นต่อกันของการฉีด เพียงเพราะคุณทำให้มันเป็นพารามิเตอร์ไม่ได้หมายความว่า obj รับประกันว่าจะมีสถานะคงที่ ฟังก์ชั่นบางอย่างที่คุณอาจเรียกไปยังฟังก์ชั่นอื่นที่ปรับเปลี่ยนสถานะของตัวแปรฉีดที่ด้านบน
Pacerier

34

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

ลองนึกภาพการดีบักโปรแกรมที่ไม่รู้จัก: คุณพบว่าฟังก์ชัน A ทำงานในลักษณะที่แน่นอนสำหรับพารามิเตอร์อินพุตบางอย่าง แต่บางครั้งก็ทำงานแตกต่างกันสำหรับพารามิเตอร์เดียวกัน คุณจะพบว่ามันใช้ตัวแปรทั่วโลกx

คุณมองหาสถานที่ที่ปรับเปลี่ยนxและพบว่ามีห้าแห่งที่แก้ไขได้ ตอนนี้ขอให้โชคดีในการค้นพบว่าฟังก์ชัน A ทำอะไร ...


ดังนั้นไม่เปลี่ยนรูปของรัฐทั่วโลกไม่ได้เป็นความชั่วร้ายเพื่อ?
FrustratedWithFormsDesigner

50
ฉันจะบอกว่ารัฐโลกที่ไม่เปลี่ยนรูปนั้นเป็นวิธีปฏิบัติที่ดีที่รู้จักกันดีในชื่อ 'ค่าคงที่'
Telastyn

6
รัฐโลกที่ไม่เปลี่ยนรูปนั้นไม่เลวร้ายเพียง :-) มันยังคงเป็นปัญหาอยู่เนื่องจากการมีเพศสัมพันธ์ที่จะแนะนำ (ทำการเปลี่ยนแปลงการใช้ซ้ำและการทดสอบหน่วยให้หนักขึ้น) แต่สร้างปัญหาได้น้อยกว่ามากดังนั้นในกรณีง่าย ๆ ก็มักจะยอมรับได้
sleske

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

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

9

คุณเรียงลำดับจากตอบคำถามของคุณเอง พวกเขายากที่จะจัดการเมื่อ 'ถูกทารุณกรรม' แต่อาจมีประโยชน์และ [ค่อนข้าง] สามารถคาดเดาได้เมื่อใช้อย่างถูกต้องโดยคนที่รู้วิธีบรรจุพวกเขา การบำรุงรักษาและการเปลี่ยนแปลง / บนดาวกลมมักเป็นฝันร้ายทำให้แย่ลงเมื่อขนาดของแอปพลิเคชันเพิ่มขึ้น

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

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


9

มีปัญหามากมายเกี่ยวกับ Singletons - นี่คือสองปัญหาใหญ่ที่สุดในใจของฉัน

  • ทำให้การทดสอบหน่วยเป็นปัญหา สถานะโลกสามารถปนเปื้อนจากการทดสอบหนึ่งไปยังอีก

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

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

ทางเลือกสำหรับ Singleton คือการสร้าง Big Global Objects เหล่านี้เมื่อเริ่มต้นและส่งผ่านเป็นพารามิเตอร์ของคลาสหรือวิธีการทั้งหมดที่ต้องการเข้าถึงวัตถุนี้

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

คุณพบปัญหาการบำรุงรักษาใหม่ ตัวอย่าง: ทันใดนั้น "WidgetFactory" ของคุณองค์ประกอบที่อยู่ลึกลงไปในกราฟต้องมีวัตถุตัวจับเวลาที่คุณต้องการเยาะเย้ย อย่างไรก็ตาม "WidgetFactory" ถูกสร้างขึ้นโดย "WidgetBuilder" ซึ่งเป็นส่วนหนึ่งของ "WidgetCreationManager" และคุณต้องมีสามคลาสที่รู้เกี่ยวกับวัตถุตัวจับเวลานี้แม้ว่าจะมีเพียงหนึ่งจริงใช้ คุณพบว่าตัวเองต้องการที่จะยอมแพ้และเปลี่ยนกลับสู่ Singletons และเพียงแค่ทำให้วัตถุตัวจับเวลานี้เข้าถึงได้ทั่วโลก

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

ดังนั้นโดยสรุป Singletons ไม่ดีและทางเลือกคือการใช้กรอบการฉีดพึ่งพา

ฉันบังเอิญใช้ Castle Windsor แต่คุณมีทางเลือกมากมาย ดูหน้านี้ย้อนหลังได้ในปี 2008 เพื่อดูรายการเฟรมเวิร์กที่มีอยู่


8

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

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

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

Btw ... บางคนคิดว่าการฉีดพึ่งพานั้นไม่ดีรวมถึงผู้สร้าง Linq แต่นั่นจะไม่หยุดคนที่ใช้งานรวมถึงตัวฉันเอง ประสบการณ์ในท้ายที่สุดจะเป็นครูที่ดีที่สุดของคุณ มีบางครั้งที่จะปฏิบัติตามกฎและเวลาที่จะทำลายพวกเขา


4

เนื่องจากบางคำตอบอื่น ๆ ที่นี่จะทำให้ความแตกต่างระหว่างที่ไม่แน่นอนและไม่เปลี่ยนรูปของรัฐทั่วโลกผมอยากจะมีความคิดเห็นว่าแม้จะไม่เปลี่ยนรูปตัวแปรทั่วโลก / การตั้งค่ามักจะแกล้ง

พิจารณาคำถาม:

... สมมติว่าฉันต้องการการกำหนดค่าทั่วโลกสำหรับแอปพลิเคชันของฉันเช่นเส้นทางโฟลเดอร์ระบบหรือหนังสือรับรองฐานข้อมูลทั่วทั้งแอปพลิเคชัน ...

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

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


3

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

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

(นี่ไม่ใช่ตัวอย่างแบบสุ่ม ... สิ่งนี้เกิดขึ้นกับระบบการกำหนดค่าของเราในโครงการที่ฉันกำลังเข้ามา)

เมื่อพิจารณาว่าค่าใช้จ่ายในการทำสิ่งที่ไม่ใช่โลกเป็นเรื่องไม่สำคัญมันเป็นเรื่องโง่ที่จะทำเช่นนั้น คุณกำลังสร้างปัญหาในอนาคต


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

3

ปัญหาอื่น ๆ ที่อยากรู้อยากเห็นก็คือพวกเขาทำให้แอปพลิเคชันยากต่อการปรับขนาดเพราะมันไม่ได้เป็น "โลก" เพียงพอ ขอบเขตของตัวแปรทั่วโลกเป็นกระบวนการ

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


3

ทำไมรัฐโลกถึงชั่วร้าย?

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

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


3

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

Joe-Eเป็นตัวอย่างหนึ่งและ David Wagner อธิบายการตัดสินใจดังนี้:

การวิเคราะห์ว่าใครสามารถเข้าถึงออบเจ็กต์และหลักการของสิทธิพิเศษอย่างน้อยที่สุดจะถูกล้มเลิกเมื่อความสามารถถูกเก็บไว้ในตัวแปรส่วนกลางและทำให้ส่วนใดส่วนหนึ่งของโปรแกรมสามารถอ่านได้ เมื่อวัตถุพร้อมใช้งานทั่วโลกจะไม่สามารถ จำกัด ขอบเขตของการวิเคราะห์ได้อีกต่อไป: การเข้าถึงวัตถุนั้นเป็นสิทธิ์พิเศษที่ไม่สามารถยับยั้งได้จากรหัสใด ๆ ในโปรแกรม Joe-E หลีกเลี่ยงปัญหาเหล่านี้โดยการตรวจสอบว่าขอบเขตทั่วโลกไม่มีความสามารถเพียงข้อมูลที่ไม่เปลี่ยนรูป

ดังนั้นวิธีคิดอย่างหนึ่งคือ

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

ดังนั้นสถานะที่ไม่แน่นอนทั่วโลกทำให้ยากขึ้น

  1. ออกแบบระบบที่แข็งแกร่ง
  2. ยากที่จะพิสูจน์คุณสมบัติของระบบและ
  3. ยากที่จะตรวจสอบให้แน่ใจว่าการทดสอบของคุณกำลังทดสอบในขอบเขตที่ใกล้เคียงกับสภาพแวดล้อมการผลิตของคุณ

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


2

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

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

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

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

นอกจากนี้:ปัญหามัลติเธรด:

(โปรดทราบว่าคุณสามารถมีปัญหาที่คล้ายกันกับคิวเหตุการณ์หรือการโทรซ้ำ แต่การมัลติเธรดนั้นแย่ที่สุด) พิจารณารหัสต่อไปนี้:

if (filePath != null)  text = filePath.getName();

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

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

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


1
คุณสามารถอธิบายสิ่งที่คุณหมายถึงโดยสิ่งนี้ได้หรือไม่: "สิ่งใด ๆ ที่ไม่ใช่ตัวแปรท้องถิ่นหรือฟิลด์ที่ไม่สามารถเปลี่ยนแปลงได้นั้นเป็นปัญหาลูกโลกนั้นเป็นปัญหาประเภทนี้ แต่คุณจะไม่แก้ไขด้วยการทำให้มันไม่ใช่โลก"
Andres F.

1
@AndresF: ฉันขยายคำตอบของฉัน ฉันคิดว่าฉันใช้วิธีเดสก์ท็อปที่คนส่วนใหญ่ในหน้านี้มีรหัสเซิร์ฟเวอร์กับฐานข้อมูลมากขึ้น "ทั่วโลก" อาจหมายถึงสิ่งต่าง ๆ ในกรณีเหล่านี้
RalphChapin

2

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

เหตุผลที่แท้จริงที่จะไม่ใช้ที่เก็บข้อมูลส่วนกลางคือเพื่อหลีกเลี่ยงการชนกันของชื่อ หากคุณโหลดหลายโมดูลที่ประกาศชื่อโกลบอลเดียวกันคุณอาจมีพฤติกรรมที่ไม่ได้กำหนด (ยากมากที่จะทำการดีบักเนื่องจากการทดสอบหน่วยจะผ่าน) หรือข้อผิดพลาด linker (ฉันคิดว่า C - ตัวเชื่อมโยงของคุณเตือนหรือล้มเหลวหรือไม่?)

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


1

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

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


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

1

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

สำหรับสถานะโลกไม่มีปัญหาดังกล่าวทุกอย่างเป็นของโลก

ตัวอย่างเช่น: ลองจินตนาการถึงสถานการณ์ต่อไปนี้: คุณมีตารางขนาด 10x10 ซึ่งทำจาก "กระดาน" และ "ไทล์" แบบคลาสสิก

ถ้าคุณต้องการที่จะทำมันด้วยวิธี OOP คุณอาจจะผ่านวัตถุ "บอร์ด" ไปยัง "ไทล์" แต่ละอัน สมมติว่าตอนนี้ "ไทล์" มีเขตข้อมูลประเภท 2 "ไบต์" ซึ่งจัดเก็บเป็นพิกัด หน่วยความจำทั้งหมดที่ใช้กับเครื่อง 32 บิตสำหรับหนึ่งไทล์จะเป็น (1 + 1 + 4 = 6) ไบต์: 1 สำหรับ x coord, 1 สำหรับ y coord และ 4 สำหรับตัวชี้ไปยังบอร์ด สิ่งนี้ให้ผลรวม 600 ไบต์สำหรับการตั้งค่าไทล์ 10x10

ตอนนี้สำหรับกรณีที่คณะกรรมการอยู่ในขอบเขตส่วนกลางวัตถุเดียวที่สามารถเข้าถึงได้จากแต่ละไทล์ที่คุณจะต้องได้รับ 2 ไบต์ของหน่วยความจำต่อแต่ละไทล์นั่นคือพิกัด x และ y สิ่งนี้จะให้เพียง 200 ไบต์

ดังนั้นในกรณีนี้คุณจะได้รับ 1/3 ของการใช้หน่วยความจำหากคุณใช้สถานะโกลบอลเท่านั้น

สิ่งนี้นอกเหนือจากสิ่งอื่น ๆ ฉันคิดว่าเป็นเหตุผลว่าทำไมขอบเขตทั่วโลกยังคงอยู่ในภาษาระดับต่ำ (ค่อนข้าง) เช่น C ++


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

1
@MadaraUchiha ไม่อาร์กิวเมนต์นี้ไม่สั่นคลอน แต่อย่างใด นั่นคือข้อเท็จจริงวัตถุประสงค์เว้นแต่ว่า VM หรือภาษาที่คอมไพล์อื่น ๆ จะทำการเพิ่มประสิทธิภาพโค้ดที่ไม่ยอมใครง่ายๆกับปัญหาประเภทนี้ มิฉะนั้นมันก็ยังเกี่ยวข้อง แม้จะมีโปรแกรมฝั่งเซิร์ฟเวอร์ซึ่งใช้เป็น "หนึ่ง shot" หน่วยความจำจะถูกสงวนไว้ตลอดเวลาของการดำเนินการ ด้วยโหลดเซิร์ฟเวอร์ที่สูงนี่อาจเป็นจุดวิกฤติ
luke1985

0

มีหลายปัจจัยที่ต้องพิจารณากับสถานะโลก:

  1. พื้นที่หน่วยความจำโปรแกรมเมอร์
  2. รูปกลมที่ไม่เปลี่ยนรูป / เขียนรอบตัวครั้งเดียว
  3. กลมกลืนไม่แน่นอน
  4. พึ่งพาพึ่งกลม

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

Immutables / write หนึ่งครั้งโดยทั่วไปจะเป็น OK แต่ระวังข้อผิดพลาดในการเริ่มต้นลำดับ

globals ที่เปลี่ยนแปลงได้มักถูกเข้าใจผิดว่าเป็น globals ที่ไม่เปลี่ยนรูป ...

ฟังก์ชั่นที่ใช้ globals อย่างมีประสิทธิภาพมีพารามิเตอร์ "ซ่อน" เป็นพิเศษทำให้การปรับโครงสร้างนั้นยากขึ้น

รัฐโลกไม่ใช่ความชั่วร้าย แต่มันมีค่าใช้จ่ายที่แน่นอน - ใช้มันเมื่อผลประโยชน์มีมากกว่าค่าใช้จ่าย

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