แทนอินสแตนซ์ของ Java?


10

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

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

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

มีวิธีที่ดีกว่าในการทำเช่นนี้หรือฉันติดอยู่กับการใช้instanceofหรือการสะท้อนบางอย่างเพื่อให้ได้ฟิลด์ที่เฉพาะเจาะจงกับวัตถุ


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

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

คำตอบ:


16

เหตุผลที่instanceofท้อแท้ก็คือไม่ใช่ OOP

ไม่ควรมีเหตุผลใด ๆ ที่ผู้โทร / ผู้ใช้ของวัตถุจะรู้ได้ว่าคลาสใดที่เป็นรูปธรรมซึ่งเกินกว่าที่จะประกาศตัวแปรประเภทนั้น

หากคุณต้องการพฤติกรรมที่แตกต่างในคลาสย่อยให้เพิ่มวิธีการและนำไปปฏิบัติต่างกัน


1
ดังนั้นวิธีการgetSpecifics()(หรือสิ่งที่คล้ายกัน) ในแต่ละชั้นเรียนที่จะส่งกลับเฉพาะสำหรับแต่ละชั้นเรียน นี่เป็นวิธีที่ดีที่สุดหรือไม่?
โทมัสมิทเชล

@Schmooo คุณต้องคิดเกี่ยวกับการใช้งานฟังก์ชั่นทั่วไปที่มีอยู่ในแผนผังชั้นเรียนและสัญญาที่มีอยู่ในแต่ละระดับ

3
แต่สิ่งที่เกี่ยวกับกรณีที่วัตถุของคุณข้ามเลเยอร์และข้อมูลประเภทจะหายไป? Listตัวอย่างผมสร้าง ฉันผ่านมันไปยังวัตถุที่รับIterableได้ ตอนนี้วัตถุที่สองส่งผ่านไปยังวัตถุที่สามซึ่งใช้ a Listสำหรับการออปติไมซ์หรือIterableแต่ช้ากว่ามาก ที่สองไม่ควรรู้ว่ามันเป็นรายการ แต่คนที่สามอยากจะรู้ ไม่ควรตรวจสอบวัตถุที่สามเพื่อหา instanceof เพื่อดูว่าสามารถใช้การปรับให้เหมาะสมได้หรือไม่ ดูตัวอย่างฝรั่งFluentIterableที่ทำแบบนั้น
Laurent Bourgault-Roy

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

9

instanceof ไม่จำเป็นต้องเป็นสิ่งที่ไม่ดี แต่มันเป็นสิ่งที่เราควรพิจารณา

ตัวอย่างของการทำงานอย่างถูกต้องอยู่ในสถานที่ที่หนึ่งได้รับคอลเลกชันของประเภทฐานและคุณต้องการให้คนประเภทย่อย การรับที่อยู่เครือข่ายจากการNetworkInterface.getNetworkInterfaces()ส่งคืนวัตถุ NetworkInterface ที่มีการรวบรวมวัตถุ InetAddress ซึ่งบางส่วนเป็น Inet4Address และบางส่วนเป็น Inet6Address หากต้องการกรองคอลเลกชันสำหรับวัตถุ Inet4Address ก็จำเป็นต้องใช้อินสแตนซ์ของ

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

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

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


เป็นไปได้ว่ามีอินเตอร์เฟซระบุวิธีการอาจจะเป็นวิธีที่ดีกว่าการกรองสำหรับคุณภาพเช่นกว่าการตรวจสอบประเภทคอนกรีตผ่านisOfType(SomeEnum.IPv4) instanceofถ้าคุณต้องการแบ่งคลาสการใช้งาน IPv4 ของคุณในภายหลัง ไม่ใช่ว่ามันจะดีกว่าเสมอ แต่เป็นการพิจารณา
Steven Schlansker

@StevenSchlansker ที่สามารถทำงานในชั้นเรียนที่เฉพาะเจาะจง แต่ถ้าหากใครต้องการตรวจสอบประเภทที่เป็นรูปธรรมเพื่อดูว่ามีความเป็นไปได้หรือไม่ มันจะเป็นการยากที่จะทำงานกับส่วนต่อประสาน (enum ที่แจกแจงทุกคลาสในแพ็คเกจหรือคลาสโหลดเดอร์) และนั่นหมายความว่าวิธีการนั้นจะต้องดำเนินการด้วยมือ (หรือรหัสสะท้อนใน Object) (o instanceof Serializable) || (o instanceof Externalizable)พิจารณาวิธีการที่จะทำ อินสแตนซ์ของดีกว่าทางเลือก

1

คุณสามารถใช้วิธี getClass ()

คุณแน่ใจหรือว่าต้องการสามคลาสที่แตกต่างกัน? บางทีคลาสหนึ่งที่มีสวิตช์ด้านในจะให้บริการดีกว่า


7
getClassและinstanceofแบ่งปันข้อเสีย ความแตกต่างนั้นดีกว่าทั้งสองอย่างเมื่อมันเข้ากันได้ดีและฉันไม่เห็นว่ามันไม่เหมาะกับกรณีการใช้ของ OP

ฉันไม่มีอะไรเทียบกับประโยคแรกของคุณ แต่อันที่สอง - ขอโทษฉันไม่เข้าใจว่าคุณหมายความว่าอย่างไร
Gangnus

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

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

2
@Gangus ฉันไม่คิดว่านี่เป็น "การโจมตี" ฉันหมายถึงไม่มีความผิด แต่อะไรก็ตาม ไม่คำถามไม่ใช่ "สิ่งอื่นที่สามารถใช้ได้" แต่เป็น "มีวิธีที่ดีกว่าในการทำเช่นนี้" ถ้าคุณไม่ต้องการโต้แย้งgetClassเป็นวิธีที่ดีกว่าที่จะทำมันไม่มีธุรกิจตอบคำถาม ;-)

1

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

มีหลายครั้งที่ฉันหวังว่าฉันจะมีวิธีในการจัดส่งแบบไดนามิกและบันทึกรหัสจานหม้อน้ำจำนวนหนึ่งและป้องกันโครงสร้างวัตถุของฉันในอนาคต C # ให้คำสำคัญแบบไดนามิกในการติดตั้งใหม่ของกรอบ แต่เท่าที่ฉันรู้ Java ยังไม่ได้มีสิ่งที่คล้ายกัน

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

หวังว่านี่จะช่วยได้

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