ทำให้วิธีการที่ไม่ขึ้นอยู่กับเขตข้อมูลอินสแตนซ์คงที่?


19

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

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


วิธีการเหล่านี้เรียกวิธีการอื่น ๆ เช่น? หรือว่าพวกเขาไม่มีอะไรเกี่ยวข้องกับวัตถุในชั้นเรียนเลย? คุณยกตัวอย่างได้ไหม
Ray Toal

คำตอบ:


26

ทราบว่ามีความคิดนี้การตรวจสอบสำหรับ Java เป็นอย่างดีก็จะเรียกว่าวิธีการอาจจะ 'คงที่' ,

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

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

เริ่มต้นด้วยการสอน Java อย่างเป็นทางการค่อนข้าง จำกัด เมื่อวิธีการควรจะคงที่:

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

จากด้านบนอาจกล่าวได้ว่าการเปิดการตรวจสอบตามค่าเริ่มต้นนั้นไม่สอดคล้องกับการใช้งานตัวดัดแปลงแบบคงที่ที่แนะนำใน Java

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

ดูตัวอย่างบทความ Java World - Mr. Happy Object สอนวิธีการคงที่ :

วิธีการใด ๆ ที่เป็นอิสระจากสถานะของอินสแตนซ์เป็นผู้สมัครที่ถูกประกาศว่าเป็นแบบคงที่

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

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

บทความที่บล็อกการทดสอบของ Google แม้จะไปไกลเท่าที่อ้างว่าวิธีการแบบคงที่เป็นความตายต่อการตรวจสอบได้ :

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

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


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

นักพัฒนา IDE จะมีเวลาอธิบายยากมากว่าทำไมพวกเขาคิดว่ามันสำคัญมากที่จะต้องตั้งไว้เป็นค่าเริ่มต้นเทียบกับข้อเสนอแนะที่ได้รับการยอมรับและแนวทางปฏิบัติที่ดีที่สุด

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

หากคลาส Groovy ที่คุณกำลังทำการทดสอบเรียกใช้วิธีการคงที่ในคลาส Groovy อื่นคุณสามารถใช้ ExpandoMetaClass ซึ่งช่วยให้คุณสามารถเพิ่มเมธอด constructors คุณสมบัติและเมธอดแบบไดนามิก ...

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

"เฮ้วิธีนี้ไม่ได้ใช้ฟิลด์อินสแตนซ์ทำไมคุณไม่เตือนฉันถึงเรื่องนี้" คำถามนั้นจะตอบได้ง่ายสำหรับ Java (ตามที่อธิบายข้างต้น) แต่สำหรับ Groovy ไม่มีคำอธิบายที่น่าสนใจ


โดยวิธีการ ReSharper (ทำโดย JetBrains สำหรับ C # / Visual Studio) แนะนำสิ่งเดียวกัน
Konrad Morawski

6
มีความแตกต่างที่สำคัญระหว่างวิธีการคงที่มีและไม่มีผลข้างเคียงคือ สารสกัดจาก Google กล่าวถึงอดีต
assylias

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

5

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

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


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

2
@ user40980 มันควรค่าแก่การพิจารณาจริง ๆ แต่ก็ควรพิจารณาด้วยว่าการสืบทอดอาจเป็นเครื่องมือที่มักใช้ในทางที่ผิดและตัวเลขที่โดดเด่นหลายคนยืนยันว่าคลาสทั้งหมดควรได้finalรับการออกแบบมาโดยเฉพาะ
sara

3

ฉันคิดว่ามันคือการเปิดใช้ refactoring ไปได้ที่จะเห็น

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

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


-1

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

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


คำถามนี้ถามคำถามนี้อย่างไร
ริ้น

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