ทำไมตัวแปรแบบคงที่จึงถือว่าชั่วร้าย?


635

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

ฉันพบว่าตัวแปรคงที่สะดวกในการใช้ และฉันคิดว่าพวกเขามีประสิทธิภาพด้วย (โปรดแก้ไขให้ฉันถ้าฉันผิด) เพราะถ้าฉันต้องโทร 10,000 ครั้งไปยังฟังก์ชั่นหนึ่งในชั้นเรียนฉันก็ดีใจที่ทำให้วิธีนี้คงที่และใช้วิธีตรงไปตรงมาClass.methodCall()แทน ถ่วงหน่วยความจำที่มี 10,000 อินสแตนซ์ของคลาสใช่มั้ย

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

ป.ล. : โปรดแก้ไขให้ถูกต้องหากข้อสันนิษฐานของฉันเกี่ยวกับสถิตศาสตร์นั้นไม่ถูกต้อง


43
เพียงเพื่อพูดว่าไม่มีตัวแปรคงที่หรือวิธีการใน Smalltalk หรือ Scala เพราะวิธีการคงที่และตัวแปรที่ขัดกับหลักการ OOP
Maurício Linhares

87
อย่างน้อยหนึ่งประโยคที่คุณทำค่อนข้างแปลก: "สถิตศาสตร์ลดการพึ่งพาระหว่างส่วนอื่น ๆ ของรหัส" โดยทั่วไปแล้วพวกเขากระชับการพึ่งพา รหัสที่การโทรถูกผูกไว้แน่นมากกับรหัสที่เรียก ไม่มีสิ่งที่เป็นนามธรรมระหว่างการพึ่งพาโดยตรง
Arne Deutsch

11
คำถามที่ดี ... มีคำถามเพิ่มเติมอีกมากมายจากโปรแกรมเมอร์
WernerCD

26
วรรคสองของคุณเกี่ยวกับเรื่องที่แตกต่างอย่างสิ้นเชิงคือแบบคงที่วิธีการ
พอล

8
ฟังก์ชั่นการเขียนโปรแกรมยังขมวดคิ้วเมื่อรัฐทั่วโลกเช่นกัน หากคุณเคยเข้าร่วม FP ในวันใดวันหนึ่ง(และคุณควร ) เตรียมที่จะทิ้งแนวความคิดของรัฐทั่วโลก
new123456

คำตอบ:


689

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

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


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

144
@ Platvoet ฉัน: ฉันจะบอกว่าให้เลือกระหว่างสองการออกแบบที่ถูกต้องเป็นอย่างอื่นอย่างเท่าเทียมกันหนึ่งที่ทดสอบได้ดีกว่า ถูกทดสอบอย่างแน่นอนไม่ได้ถือเอาการที่ถูกออกแบบมาอย่างดี แต่ฉันไม่ค่อยเจอการออกแบบที่ดี untestable และผมคิดว่าพวกเขากำลังหายากพอสมควรที่ผมมีปัญหาในการตรวจสอบได้ไม่มีอเนกประสงค์ที่เอื้อต่อการบ่งชี้การออกแบบที่ดี
Jon Skeet

9
@ M Platvoet - ความสามารถในการทดสอบมีผลต่อทั้งการบำรุงรักษาและความน่าเชื่อถือและฉันจะพิจารณาปัจจัยสำคัญเหล่านั้นในคุณภาพของการออกแบบ พวกเขาไม่ได้เป็นเพียงปัจจัยอย่างแน่นอน แต่ IMHO ค่าใช้จ่ายของรหัสที่กำหนดคือการรวมกันของรอบเครื่องรอบนักพัฒนาและรอบผู้ใช้ ความสามารถในการทดสอบนั้นมีสองในสาม
จัสตินมอร์แกน

5
@M Platvoet - ความสามารถในการทดสอบมีแนวโน้มที่จะส่งผลต่อการนำมาใช้ใหม่ได้เนื่องจากคลาสที่แยกได้นั้นมักจะนำมาใช้ซ้ำได้ง่ายขึ้น
TrueWill

13
M Platvoet - ฉันไม่เห็นด้วยกับความคิดเห็นแรกของคุณที่นี่ ฉันคิดว่าถ้าบางสิ่งไม่สามารถทดสอบได้แสดงว่ามันไม่ดี เพราะถ้าฉันไม่สามารถทดสอบได้ฉันก็ไม่รู้ว่ามันใช้งานได้จริง คุณจะซื้อรถไหมถ้าพนักงานขายบอกคุณว่า "การออกแบบของรุ่นนี้ป้องกันไม่ให้ถูกทดสอบดังนั้นฉันไม่รู้ว่ามันทำงานจริงหรือไม่" ความสามารถในการทดสอบนั้นมีความสำคัญอย่างยิ่งต่อซอฟต์แวร์ (เช่นเดียวกับรถยนต์) ซึ่งการออกแบบที่มีความสามารถนั้นต้องรวมไว้ด้วย
Dawood ibn Kareem

277

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

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

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

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

ตัวเลือกอื่น: หากประสิทธิภาพเป็นปัญหาหลักของคุณอาจมีวิธีอื่นที่ดีกว่าในการแก้ปัญหาความเร็วมากกว่าการพิจารณาเฉพาะข้อดีของการเรียกใช้ที่มักจะเร็วกว่าการสร้าง พิจารณาว่าจำเป็นต้องมีการปรับเปลี่ยนชั่วคราวหรือเปลี่ยนแปลงได้ทุกที่ เพื่อรักษาความสามารถในการอินไลน์วิธีการอาจถูกทำเครื่องหมายเป็นขั้นสุดท้ายแทนแบบคงที่ พารามิเตอร์วิธีการและตัวแปรอื่น ๆ สามารถทำเครื่องหมายสุดท้ายเพื่อให้การเพิ่มประสิทธิภาพของคอมไพเลอร์บางอย่างขึ้นอยู่กับสมมติฐานเกี่ยวกับสิ่งที่สามารถเปลี่ยนแปลงตัวแปรเหล่านั้น วัตถุอินสแตนซ์สามารถนำกลับมาใช้ซ้ำได้หลายครั้งแทนที่จะสร้างอินสแตนซ์ใหม่ในแต่ละครั้ง อาจมีสวิตช์ปรับให้เหมาะสมของ compliler ที่ควรเปิดสำหรับแอปโดยทั่วไป บางทีการออกแบบควรมีการตั้งค่าเพื่อให้สามารถรัน 10,000 เธรดแบบมัลติเธรดและใช้ประโยชน์จากคอร์โปรเซสเซอร์แบบมัลติ ถ้า portablity isn '

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


11
ฉันชอบคำตอบของคุณฉันคิดว่ามันมุ่งเน้นไปที่การแลกเปลี่ยนที่ถูกต้องเพื่อพิจารณาเกี่ยวกับสถิตยศาสตร์มากกว่าฝูงปลาสีแดงบางอย่างเช่นการเกิดพร้อมกันและขอบเขต และ +1 สำหรับ singletons เป็นคำถามที่ดีกว่าจริงๆอาจจะได้รับเมื่อมีการใช้ตัวแปรคงที่ / วิธีการเทียบ singletons ...
studgeek

2
แม้ว่าตัวซิงเกิลนั้นอาจเป็น thread-safe (เช่นโดยการใช้synchronizedเมธอด) มันไม่ได้หมายความว่ารหัสการโทรนั้นไม่มีเงื่อนไขการแข่งขันที่เกี่ยวข้องกับสถานะ singleton
André Caron

8
นอกจากนี้สถิตศาสตร์ยังไม่ขัดกับกระบวนทัศน์ของ OOP ผู้คลั่งไคล้ OOP จำนวนมากจะบอกคุณว่าคลาสเป็นวัตถุและเมธอดแบบสแตติกเป็นวิธีการของคลาสอ็อบเจ็กต์แทนที่จะเป็นอินสแตนซ์ ปรากฏการณ์นี้มีอยู่น้อยใน Java ภาษาอื่นเช่น Python อนุญาตให้คุณใช้คลาสเป็นตัวแปรและคุณสามารถเข้าถึงวิธีการคงที่เป็นวิธีการของวัตถุนั้น
André Caron

4
ควรอ่านบรรทัดสุดท้ายของย่อหน้าที่สามซึ่งเป็นตัวแปรคงที่ทั้งหมดของคุณหากฉันไม่เข้าใจผิด
Steve

1
Object Lifetimeเป็นหนึ่งในจุดสำคัญที่ @jessica พูดถึง
Abhidemon

93

ความชั่วร้ายเป็นศัพท์เฉพาะ

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

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

นี่เป็นสองประเด็นหลักที่ฉันมีกับพวกเขา


59

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

รัฐทั่วโลกมีความจำเป็นอย่างยิ่ง เราไม่สามารถหลีกเลี่ยงสถานะโลก เราไม่สามารถหลีกเลี่ยงเหตุผลเกี่ยวกับสถานะโลก - ถ้าเราใส่ใจที่จะเข้าใจความหมายใบสมัครของเรา

คนที่พยายามกำจัดรัฐโลกเพื่อผลประโยชน์ของมันย่อมต้องจบลงด้วยระบบที่ซับซ้อนมากขึ้นและรัฐโลกยังคงอยู่ที่นั่นปลอมตัว / งี่เง่าอย่างชาญฉลาดภายใต้ความกดดันหลายชั้น และเรายังคงต้องให้เหตุผลเกี่ยวกับรัฐทั่วโลกหลังจากแก้ปัญหาทางอ้อมทั้งหมด

เช่นเดียวกับคนในฤดูใบไม้ผลิที่ประกาศสถานะโลกอย่างฟุ่มเฟือยใน xml และคิดว่ามันยอดเยี่ยม

@ จอน Skeet if I create a new instance of an objectตอนนี้คุณมีสองสิ่งที่ต้องให้เหตุผลเกี่ยวกับ - สถานะภายในวัตถุและสถานะของสภาพแวดล้อมที่โฮสต์วัตถุ


10
"ฉันมีสองสิ่งที่ต้องให้เหตุผล" ไม่ใช่ถ้าฉันทำการทดสอบของฉันขึ้นอยู่กับสถานะของวัตถุเท่านั้น ไหนจะง่ายกว่าโลกที่ฉันมีอยู่น้อยลง
DJClayworth

2
การพึ่งพาการฉีดไม่มีส่วนเกี่ยวข้องกับสภาวะของโลกหรือทัศนวิสัยระดับโลก - แม้แต่ตัวของมันเองก็ไม่ได้เป็นของโลก เมื่อเทียบกับรหัส "ปกติ" สิ่งพิเศษเฉพาะที่มองเห็นวัตถุที่จัดการคอนเทนเนอร์คือตัวของคอนเทนเนอร์ ในความเป็นจริง DI มักใช้เพื่อหลีกเลี่ยงรูปแบบซิงเกิล
Floegipoky

31

มี 2 ​​ปัญหาหลักเกี่ยวกับตัวแปรคงที่:

  • ความปลอดภัยของเธรด - ทรัพยากรแบบสแตติกตามคำจำกัดความที่ไม่ปลอดภัยสำหรับเธรด
  • Code Implicity - คุณไม่ทราบว่าเมื่อใดที่ตัวแปรสแตติกถูกสร้างอินสแตนซ์และจะสร้างอินสแตนซ์ก่อนหรือไม่ตัวแปรสแตติกอื่น

ฉันคิดว่า Jon Skeet อ้างถึงความคิดเห็นเดียวกับที่คุณโพสต์
RG-3

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

1
@Zmaster - ในขณะที่มันเป็นความจริงว่าด้ายความปลอดภัยไม่ได้เป็นปัญหา แต่เพียงผู้เดียวในการตัวแปรคงเพราะโดยความหมายของพวกเขาพวกเขาจะถูกเรียกจากและบริบทที่แตกต่างที่พวกเขามีลูกพรุนมากขึ้นกับพวกเขา
sternr

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

มีการใช้เธรดที่ปลอดภัยที่ถูกต้องของทรัพยากรสแตติกตัวอย่างเช่น ส่วนตัวคง Logger สุดท้าย Log = Logger.getLogger (Foo.class); ส่วนตัวคงสุดท้าย AtomicInteger x = ใหม่ AtomicInteger (0); ตามที่ฉันเข้าใจแล้วการกำหนดค่าคงที่ของทรัพยากรเช่นนี้รับประกันความปลอดภัยของเธรดโดยตัวโหลดคลาส อินสแตนซ์ของคนตัดไม้คือหรือไม่ปลอดภัยกับเธรดที่คุณกำหนดตัวชี้ให้กับมัน การรักษาสถานะในสถิตยศาสตร์อาจไม่ใช่ความคิดที่ดี แต่ไม่มีเหตุผลใดที่มันไม่ควรปลอดภัยต่อเธรด
teknopaul

29

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

ฉันจะประมาณบางแห่งประมาณ 85% ของเวลาที่ฉันเห็น 'คงที่' โดยไม่ต้อง 'สุดท้าย' มันผิด บ่อยครั้งที่ฉันจะพบวิธีแก้ปัญหาที่แปลกประหลาดเพื่อปกปิดหรือซ่อนปัญหาเหล่านี้

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

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

หากคุณต้องการรายละเอียดเพิ่มเติมโปรดอ่านต่อ ...

ทำไมไม่ใช้ Statics?

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

รหัสที่ใช้กับวัตถุสแตติกไม่สามารถทดสอบได้อย่างง่ายดายและสถิตไม่สามารถเยาะเย้ยได้ง่าย (ปกติ)

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

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

วิธีที่ดีกว่าคือสร้างอินสแตนซ์ของ CustomerDAO และส่งต่อไปยัง CustomerFilter เมื่อสร้าง (วิธีการที่ดียิ่งขึ้นคือการใช้ Spring หรือกรอบการควบคุมผกผันของการควบคุมอื่น

เมื่อคุณทำเช่นนี้คุณสามารถเยาะเย้ยหรือตอออก DAO สำรองใน CustomerFilterTest ของคุณได้อย่างรวดเร็วช่วยให้คุณสามารถควบคุมการทดสอบได้มากขึ้น

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

ดำเนินการทดสอบ

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

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

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

หากการกำหนดค่าระบบที่นำไปใช้กับส่วนประกอบเฟรมเวิร์กเหล่านี้มีการเปลี่ยนแปลงระหว่างการทดสอบหน่วยและกรอบการทดสอบหน่วยจะไม่ทำลายและสร้างส่วนประกอบขึ้นมาใหม่การเปลี่ยนแปลงเหล่านี้จะไม่มีผลบังคับใช้และเมื่อการทดสอบอาศัยการเปลี่ยนแปลงเหล่านั้น .

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

ที่แย่กว่านั้นความล้มเหลวอาจขึ้นอยู่กับลำดับที่การทดสอบรัน

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

ข้อบกพร่องที่ลึกซึ้ง

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

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

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

Anide: Static สุดท้าย

การใช้“ สแตติกสุดท้าย” นั้นเทียบเท่าจาวาของ C #define ได้อย่างมีประสิทธิภาพแม้ว่าจะมีความแตกต่างของการใช้งานด้านเทคนิค AC / C ++ #define ถูกสับเปลี่ยนจากโค้ดโดยตัวประมวลผลล่วงหน้าก่อนการคอมไพล์ จาวา "คงสุดท้าย" จะจบลงที่หน่วยความจำในกองซ้อน ด้วยวิธีนี้มันจะคล้ายกับตัวแปร "คงที่ const" ใน C ++ มากกว่าที่จะเป็น #define

สรุป

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


15

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

สถิตศาสตร์ลดการพึ่งพาระหว่างกันในส่วนอื่น ๆ ของรหัส พวกเขาสามารถทำหน้าที่เป็นผู้ถือครองรัฐที่สมบูรณ์แบบ

ฉันหวังว่าคุณพร้อมที่จะใช้การล็อคและการจัดการกับความขัดแย้ง

* อันที่จริงPreet Sanghaพูดถึงมัน


5
ตัวแปรอินสแตนซ์ไม่มีความได้เปรียบด้านความปลอดภัยของเธรดมากกว่าสถิตศาสตร์ซึ่งเป็นตัวแปรที่ไม่มีการป้องกันทั้งหมด แต่ทั้งหมดนั้นมาลงที่วิธีที่คุณปกป้องรหัสที่เข้าถึงตัวแปรเหล่านั้น
studgeek

2
ฉันไม่ได้อ้างสิทธิ์อย่างนั้น แต่เพื่อการอภิปราย: การแยกเป็นรูปแบบหนึ่งของการปกป้อง สถานะเธรดจะถูกแยกออก รัฐทั่วโลกไม่ได้ ตัวแปรอินสแตนซ์ไม่ต้องการการป้องกันเว้นแต่จะมีการแชร์อย่างชัดเจนระหว่างเธรด ตัวแปรคงเป็นมักจะใช้ร่วมกันโดยหัวข้อทั้งหมดในกระบวนการ
Justin M. Keyes

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

15

สรุปข้อดีพื้นฐานเล็กน้อยและข้อเสียของการใช้วิธีการคงที่ใน Java:

ข้อดี:

  1. เข้าถึงได้ทั่วโลกเช่นไม่ได้ผูกกับอินสแตนซ์ของวัตถุใด ๆ โดยเฉพาะ
  2. หนึ่งอินสแตนซ์ต่อ JVM
  3. สามารถเข้าถึงได้โดยใช้ชื่อคลาส (ไม่ต้องการวัตถุ)
  4. มีค่าเดียวที่ใช้กับทุกอินสแตนซ์
  5. โหลดขึ้นเมื่อเริ่มต้น JVM และตายเมื่อ JVM ปิดตัวลง
  6. พวกเขาไม่ได้แก้ไขสถานะของวัตถุ

ข้อเสีย:

  1. สมาชิกแบบสแตติกจะเป็นส่วนหนึ่งของหน่วยความจำเสมอไม่ว่าจะถูกใช้งานหรือไม่ก็ตาม
  2. คุณไม่สามารถควบคุมการสร้างและการทำลายตัวแปรแบบคงที่ได้ มีประโยชน์พวกมันถูกสร้างขึ้นที่การโหลดโปรแกรมและทำลายเมื่อยกเลิกการโหลดโปรแกรม (หรือเมื่อ JVM ปิดตัวลง)
  3. คุณสามารถทำให้เธรดสถิตปลอดภัยโดยใช้ซิงโครไนซ์ แต่คุณต้องการความพยายามพิเศษ
  4. หากหนึ่งค่าการเปลี่ยนแปลงเธรดของตัวแปรคงที่ที่สามารถทำลายการทำงานของหัวข้ออื่น ๆ
  5. คุณต้องรู้จัก“ คงที่” ก่อนใช้งาน
  6. คุณไม่สามารถแทนที่วิธีการคงที่
  7. การทำให้เป็นอันดับไม่ดีกับพวกเขา
  8. พวกเขาไม่เข้าร่วมใน polymorphism แบบ runtime
  9. มีปัญหาเกี่ยวกับหน่วยความจำ (ในระดับหนึ่ง แต่ฉันเดาไม่มาก) ถ้าใช้ตัวแปร / วิธีแบบคงที่จำนวนมาก เพราะพวกเขาจะไม่ถูกรวบรวมขยะจนกว่าโปรแกรมจะจบลง
  10. วิธีทดสอบแบบสถิตนั้นยากที่จะทดสอบเช่นกัน

ข้อเสีย 6, 7, 8 และ 10 เป็นข้อเสียของภาษา / กรอบการใช้งานและไม่ใช่ข้อเสียของตัวแปรสแตติกทั่วไป ข้อเสีย 1, 4 และ 5 ยังมีอยู่สำหรับวิธีการแก้ปัญหาอื่น ๆ เช่นรูปแบบซิงเกิลที่จัดเตรียมโดยกรอบงานบางอย่าง (ฉันไม่ได้ลงคะแนนให้คำตอบเพราะฉันเห็นด้วยส่วนที่เหลือและมันเป็นคอลเลกชันที่ดี.)
เตอร์ - Reinstate Monica

13

ถ้าฉันต้องโทร 10,000 ครั้งไปยังฟังก์ชั่นภายในชั้นเรียนฉันยินดีที่จะทำให้วิธีการแบบคงที่และใช้ class.methodCall () ตรงไปตรงมาแทนการใช้หน่วยความจำที่ยุ่งเหยิงกับคลาส 10,000 รายการใช่ไหม?

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

นอกจากนี้สถิตศาสตร์ลดการพึ่งพาระหว่างกันในส่วนอื่น ๆ ของรหัส

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

คำตอบอื่น ๆ ยังให้เหตุผลที่ดีกับการใช้สแตติคมากเกินไป


13

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

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


4
"ตัวแปรสแตติกแทนสถานะระหว่างคลาส" ... ฉันคิดว่าคุณหมายถึง "ตัวแปรสแตติกหมายถึงสถานะข้ามอินสแตนซ์"? +1 สำหรับ "ค่าคงที่ AKA สุดท้ายคงที่ไม่เลว" เนื่องจากค่าไม่สามารถเปลี่ยนแปลงได้สิ่งใดก็ตามที่ขึ้นอยู่กับค่า ณ เวลาหนึ่งจึงไม่สามารถเปลี่ยนพฤติกรรมของมันได้ในเวลาต่อมา - ค่านั้นเหมือนกัน
Jared Updike

"ตัวแปรสแตติกแทนสถานะในอินสแตนซ์" เป็นวิธีที่ดีกว่าในการระบุ ฉันแก้ไขคำตอบของฉันแล้ว
Jack Edmonds

9

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

มันเป็นเรื่องเกี่ยวกับวิธีแยกตรรกะและให้มันเป็นสถานที่ที่ดี บางครั้งที่แสดงให้เห็นถึงการใช้วิธีการคงที่ซึ่งjava.lang.Mathเป็นตัวอย่างที่ดี ฉันคิดว่าเมื่อคุณตั้งชื่อคลาสของคุณXxxUtilหรือXxxhelperคุณควรพิจารณาการออกแบบของคุณให้ดีขึ้น


3
ผลข้างเคียงที่บริสุทธิ์วิธีคงที่ฟรี IMO ที่ดีอย่างสมบูรณ์ แต่รัฐที่ไม่แน่นอนในระดับโลกนั้นไม่ค่อยมีและฉันตีความ OP ว่าพูดถึงสถานะโลก
CodesInChaos

1
@CodeInChaos เห็นด้วยทั้งหมด ฉันพบว่า OP ไม่ชัดเจนอย่างสิ้นเชิงกับความแตกต่างระหว่างวิธีการคงที่และ vars
M Platvoet

8

ฉันเพิ่งสรุปประเด็นบางข้อในคำตอบ หากคุณพบสิ่งผิดปกติโปรดแก้ไขให้ถูกต้อง

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

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

การทดสอบ:แม้ว่าการออกแบบที่ทดสอบได้จะไม่เท่ากับการออกแบบที่ดี แต่เราไม่ค่อยสังเกตการออกแบบที่ดีซึ่งไม่สามารถทดสอบได้ ในฐานะที่เป็นตัวแปรคงที่เป็นตัวแทนของรัฐทั่วโลกและมันก็ยากที่จะทดสอบพวกเขา

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

การทำให้เป็นอันดับ: การทำให้เป็นอันดับยังไม่สามารถทำงานได้ดีกับพวกเขา

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

แต่ถ้าเราต้องการมันจริงๆ

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

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


7

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

ตัวแปรสแตติกไม่ได้เลวร้าย - พวกมันมีการยอมรับว่าเป็นตัวแปรทั่วโลกเช่นค่าคงที่ในกรณีส่วนใหญ่รวมกับตัวดัดแปลงขั้นสุดท้าย แต่อย่างที่มันบอกว่าอย่าใช้มากเกินไป

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

ตัวอย่างของโปรเจ็กต์ java ที่ยอดเยี่ยมที่ใช้สแตติกจำนวนมากและทำอย่างถูกต้องโปรดดูที่Play! กรอบ นอกจากนี้ยังมีการอภิปรายเกี่ยวกับเรื่องนี้ใน SO

ตัวแปร / วิธีการแบบคงที่รวมกับการนำเข้าแบบสแตติกยังใช้กันอย่างแพร่หลายในห้องสมุดที่อำนวยความสะดวกในการเขียนโปรแกรมการประกาศในจาวาเช่น: ทำให้มันง่ายหรือHamcrest Hamcrestมันจะเป็นไปไม่ได้หากไม่มีตัวแปรและวิธีการแบบคงที่จำนวนมาก

ดังนั้นตัวแปรสแตติก (และวิธีการ) จึงดี แต่ใช้อย่างชาญฉลาด!


6

ตัวแปรสแตติกที่สำคัญที่สุดสร้างปัญหากับความปลอดภัยของข้อมูล (เมื่อใดก็ตามที่มีการเปลี่ยนแปลงทุกคนสามารถเปลี่ยนแปลงได้การเข้าถึงโดยตรงโดยไม่มีวัตถุ ฯลฯ )

สำหรับข้อมูลเพิ่มเติมอ่านนี้ ขอบคุณ


6

อาจแนะนำว่าในกรณีส่วนใหญ่ที่คุณใช้ตัวแปรแบบคงที่คุณต้องการใช้รูปแบบซิงเกิลจริงๆ

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


5

อีกเหตุผลหนึ่ง: ความเปราะบาง

หากคุณมีชั้นเรียนคนส่วนใหญ่คาดหวังว่าจะสามารถสร้างและใช้งานได้ตามต้องการ

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

หากคุณใช้ตัวแปรสแตติกจำนวนมากนั่นจะทำให้แตก บักมีราคาแพง

ระหว่าง .0001% การปรับปรุงประสิทธิภาพและความทนทานต่อการเปลี่ยนแปลงโดยนักพัฒนาที่ไม่มีทักษะในหลายกรณีความทนทานเป็นตัวเลือกที่ดี


4

ฉันพบว่าตัวแปรคงที่สะดวกในการใช้ และฉันคิดว่าพวกเขามีประสิทธิภาพด้วย (โปรดแก้ไขฉันถ้าฉันผิด) เพราะถ้าฉันต้องโทร 10,000 ครั้งไปยังฟังก์ชั่นภายในชั้นเรียนฉันยินดีที่จะทำให้วิธีการคงที่และใช้ class.methodCall ตรงไปตรงมา () บนมันแทนความยุ่งเหยิงของหน่วยความจำที่มี 10,000 อินสแตนซ์ของคลาสใช่ไหม?

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

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

อดีต:

public class WaterContainer {
    private int size;
    private int brand;
    ...etc

    public static int convertToGallon(int liters)...

    public static int convertToLiters(int gallon)...

}

คลาสสิกซิงเกิลตัน (เช่นที่เข้าถึงได้โดยClass.Instance) จะดีกว่าตัวแปรแบบคงที่ มันสามารถทดสอบได้มากกว่านี้เล็กน้อย แต่ก็ยังแย่กว่าการออกแบบที่คุณเพิ่งจะสร้างอินสแตนซ์เดียวแทนที่จะสร้างโค้ดของคุณตามสมมติฐานที่มีเพียงอันเดียว
CodesInChaos

ไม่แน่ใจว่าฉันเข้าใจความคิดเห็นของคุณ! ฉันตอบสนองต่อ OP เกี่ยวกับสิ่งที่เขากล่าวถึงเป็นตัวเอียงเกี่ยวกับการรวมวัตถุ 10,000 ชิ้น ฉันไม่เข้าใจว่าทำไมคุณเปรียบเทียบซิงเกิลตันกับตัวแปรแบบสแตติก? สิ่งที่ฉันเข้าใจจากสิ่งที่คุณเขียนคือซิงเกิลตันออกแบบไม่ดี ... ! ผมคิดว่าผมเข้าใจผิดคุณตั้งแต่ฤดูใบไม้ผลิทำให้กรอบโดยค่าเริ่มต้นถั่วทุกโทน ;-)
Cygnusx1

ซิงเกิลตันแบบคลาสสิก (ที่มีClass.Instance) ที่มีสภาวะที่ไม่แน่นอนคือ IMO ที่ออกแบบไม่ดี ในกรณีนั้นฉันชอบการออกแบบที่ฉันต้องใช้ซิงเกิลฉันต้องใช้การส่งผ่านเป็นพารามิเตอร์ในคลาสที่ใช้พวกมัน (โดยทั่วไปจะใช้ DI) ซิงเกิลคลาสสิคที่ไม่เปลี่ยนรูปแบบตามหลักเหตุผลนั้นเป็น IMO ชั้นดี
CodesInChaos

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

4

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

ฉันพบว่าตัวแปรคงที่สะดวกในการใช้ และฉันคิดว่าพวกเขามีประสิทธิภาพด้วย

สถิตเป็นทางเลือกที่เหมาะและมีประสิทธิภาพสำหรับตัวแปร / ชั้นเรียนที่ไม่เคยเปลี่ยนแปลง

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

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


"เวลาคือโลก" - มีวิธีอื่น ๆ ในการสร้างแบบจำลองเวลาในระบบคอมพิวเตอร์มากกว่าที่จะให้มันเป็นสิ่งที่ชัดเจนโดยปริยายซึ่งเป็นระดับโลกที่เปลี่ยนแปลงด้วยตัวเอง cf เลย การสำรวจนี้: "เวลาการสร้างแบบจำลองในการคำนวณ: อนุกรมวิธานและการเปรียบเทียบเชิงเปรียบเทียบ" @ arxiv.org/abs/0807.4132
Jared Updike

4

$ .02 ของฉันคือคำตอบเหล่านี้หลายอย่างทำให้เกิดปัญหาสับสนแทนที่จะพูดว่า "สถิตยศาสตร์ไม่ดี" ฉันคิดว่าการพูดคุยเกี่ยวกับการกำหนดขอบเขตและอินสแตนซ์ดีกว่า

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

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

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

สถิตยศาสตร์ไม่ใช่ "โลก" ในการกำหนดขอบเขต Java ถูกควบคุมแยกจากสแตติก / อินสแตนซ์

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

การจัดการวงจรชีวิตเป็นข้อโต้แย้งที่น่าสนใจ แต่ฉันคิดว่ามันสำคัญน้อยกว่า ฉันไม่เห็นว่าทำไมมันยากที่จะจัดการคู่ของวิธีการเรียนเช่น init () / ชัดเจน () กว่าการสร้างและทำลายอินสแตนซ์ซิงเกิล ในความเป็นจริงบางคนอาจบอกว่าซิงเกิลนั้นซับซ้อนกว่าเล็กน้อยเนื่องจาก GC

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


4

โพสต์ของคุณมีคำถามสองข้อ

ก่อนอื่นเกี่ยวกับตัวแปรสแตติก ตัวแปรสแตติกเป็นตัวแปรที่ไม่จำเป็นอย่างสมบูรณ์และสามารถหลีกเลี่ยงการใช้งานได้อย่างง่ายดาย ในภาษา OOP โดยทั่วไปและใน Java โดยเฉพาะพารามิเตอร์ฟังก์ชั่นถูกอ้างอิงโดยการอ้างอิงนี่คือถ้าคุณส่งวัตถุไปยัง funciont คุณจะส่งตัวชี้ไปยังวัตถุดังนั้นคุณไม่จำเป็นต้องกำหนดตัวแปรแบบคงที่ตั้งแต่ คุณสามารถส่งตัวชี้ไปยังวัตถุไปยังขอบเขตใด ๆ ที่ต้องการข้อมูลนี้ แม้ว่าสิ่งนี้หมายความว่า yo จะเติมหน่วยความจำของคุณด้วยพอยน์เตอร์ แต่สิ่งนี้จะไม่แสดงถึงประสิทธิภาพที่ไม่ดีเพราะระบบการแจงหน่วยความจำที่แท้จริงได้รับการปรับให้เหมาะสมในการจัดการกับสิ่งนี้ ขอบเขต; การใช้ตัวแปรแบบคงที่อาจทำให้ระบบโหลดหน้าหน่วยความจำที่พวกเขาจะถูกเก็บไว้เมื่อพวกเขาจำเป็นต้องเข้าถึง (จะเกิดขึ้นหากหน้าไม่ได้ถูก accesed ในเวลานาน) แนวทางปฏิบัติที่ดีคือการรวบรวมสแตติกทั้งหมดที่อยู่ใน "การกำหนดค่าคอนฟิเกอเรชั่น" เล็ก ๆ น้อย ๆ ซึ่งจะช่วยให้ระบบวางไว้ในหน้าหน่วยความจำเดียวกัน

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

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

PS: ขอโทษสำหรับภาษาอังกฤษของฉัน


4

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


3

a) เหตุผลเกี่ยวกับโปรแกรม

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

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

b) คุณต้องการจริงๆหรือไม่

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

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


3

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

-> แน่นอนว่าคุณสามารถบังคับใช้ เป็นเพียงตัวอย่างเดียว แต่ทำไม
ฉันพบความคิดเห็นบางส่วนในความชั่วร้ายหัวข้อนี้ไม่สถิต;)


3

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

ปัญหาปรากฏขึ้นเมื่อคุณพยายามใช้ตัวแปรแบบคงที่เพื่อเก็บค่าที่เกี่ยวข้องกับอินสแตนซ์


2

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


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

ใช่มันทำให้ดีขึ้นเพราะทำให้สามารถจัดการได้มากขึ้นในอนาคตเข้าใจได้ง่ายขึ้นและชัดเจนขึ้น
blockhead

1
ทำไมการเขียนรหัส OO ถึงมีความชั่ว และทำไม Bjarne Stroustrup ไม่เห็นด้วยกับคุณ? เพื่อชื่อเพียงหนึ่ง ...
มาร์ควิสแห่ง Lorne

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

2

มีคำตอบที่ดีมากมายที่นี่เพิ่มเข้าไป

หน่วยความจำ: ตัวแปรแบบสแตติกมีชีวิตอยู่ตราบใดที่ตัวโหลดคลาสมีชีวิตอยู่ [โดยทั่วไปจนถึง VM ตาย) แต่นี่เป็นเพียงในกรณีของวัตถุขนาดใหญ่ / การอ้างอิงที่เก็บไว้เป็นแบบคงที่

การทำให้เป็นโมดูล: พิจารณาแนวคิดเช่น IOC, dependencyInject, พร็อกซีและอื่น ๆ ทั้งหมดล้วนต่อต้านการมีเพศสัมพันธ์ / การใช้งานแบบสแตติก

ข้อต่ออื่น ๆ : ความปลอดภัยของด้าย, การทดสอบได้


0

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


0

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


0

จากมุมมองของฉันstaticตัวแปรควรจะมีเพียงเท่านั้นอ่านข้อมูลหรือตัวแปรที่สร้างขึ้นโดยการประชุม

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


0

ฉันเล่นกับสถิตยศาสตร์มากและฉันอาจให้คำตอบที่แตกต่างออกไปเล็กน้อย - หรืออาจจะเป็นวิธีที่แตกต่างออกไปเล็กน้อยในการดูมัน?

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

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

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

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