สำหรับสิ่งที่คุ้มค่าภาษาสคริปต์ส่วนใหญ่ (เช่น Perl) และภาษาคอมไพล์ไทม์แบบไม่คงที่ (เช่น Pick) รองรับการแปลงอ็อบเจ็กต์แบบไดนามิกรันไทม์อัตโนมัติ (ที่ค่อนข้างกำหนดเอง) สิ่งนี้สามารถทำได้ใน Java เช่นกันโดยไม่สูญเสียความปลอดภัยในการพิมพ์และสิ่งที่ดีภาษาที่พิมพ์แบบคงที่ให้โดยไม่มีผลข้างเคียงที่น่ารังเกียจของภาษาอื่น ๆ บางภาษาที่ทำสิ่งชั่วร้ายด้วยการหล่อแบบไดนามิก ตัวอย่าง Perl ที่ทำคณิตศาสตร์ที่น่าสงสัย:
print ++($foo = '99'); # prints '100'
print ++($foo = 'a0'); # prints 'a1'
ใน Java สิ่งนี้ทำได้ดีกว่า (IMHO) โดยใช้วิธีที่เรียกว่า "cross-casting" ด้วยการหล่อแบบไขว้จะใช้การสะท้อนในแคชของตัวสร้างและวิธีการที่โหลดแบบเกียจคร้านซึ่งค้นพบแบบไดนามิกผ่านวิธีการคงที่ต่อไปนี้:
Object fromString (String value, Class targetClass)
น่าเสียดายที่ไม่มีเมธอด Java ในตัวเช่น Class.cast () จะทำเช่นนี้สำหรับ String to BigDecimal หรือ String to Integer หรือการแปลงอื่น ๆ ที่ไม่มีลำดับชั้นของคลาสที่รองรับ ในส่วนของฉันประเด็นคือการจัดหาวิธีที่มีพลวัตอย่างเต็มที่เพื่อให้บรรลุสิ่งนี้ซึ่งฉันไม่คิดว่าการอ้างอิงก่อนหน้านี้เป็นแนวทางที่ถูกต้อง - โดยต้องเขียนโค้ดทุก Conversion พูดง่ายๆคือการใช้งานเป็นเพียงการแคสต์จากสตริงหากถูกกฎหมาย / เป็นไปได้
ดังนั้นวิธีแก้ปัญหาคือการไตร่ตรองอย่างง่าย ๆ โดยมองหาสมาชิกสาธารณะของอย่างใดอย่างหนึ่ง:
STRING_CLASS_ARRAY = (คลาสใหม่ [] {String.class});
ก) สมาชิกสมาชิก = targetClass.getMethod (method.getName (), STRING_CLASS_ARRAY); b) สมาชิกสมาชิก = targetClass.getConstructor (STRING_CLASS_ARRAY);
คุณจะพบว่าพื้นฐานทั้งหมด (Integer, Long, ฯลฯ ) และพื้นฐานทั้งหมด (BigInteger, BigDecimal ฯลฯ ) และแม้แต่ java.regex รูปแบบทั้งหมดได้รับการคุ้มครองผ่านแนวทางนี้ ฉันได้ใช้สิ่งนี้กับความสำเร็จอย่างมากในโครงการการผลิตที่มีอินพุตค่าสตริงตามอำเภอใจจำนวนมากซึ่งจำเป็นต้องมีการตรวจสอบที่เข้มงวดมากขึ้น ในแนวทางนี้หากไม่มีเมธอดหรือเมื่อมีการเรียกใช้เมธอดข้อยกเว้นจะถูกโยนทิ้ง (เนื่องจากเป็นค่าที่ไม่ถูกต้องเช่นอินพุตที่ไม่ใช่ตัวเลขไปยัง BigDecimal หรือ RegEx ที่ไม่ถูกต้องสำหรับรูปแบบ) ที่ให้การตรวจสอบเฉพาะสำหรับ ตรรกะโดยธรรมชาติของคลาสเป้าหมาย
มีข้อเสียบางประการดังนี้:
1) คุณต้องเข้าใจการไตร่ตรองให้ดี (มันซับซ้อนเล็กน้อยและไม่ใช่สำหรับมือใหม่) 2) คลาส Java และไลบรารีของบุคคลที่สามบางส่วน (แปลกใจ) ไม่ได้เข้ารหัสอย่างถูกต้อง นั่นคือมีวิธีการที่ใช้อาร์กิวเมนต์สตริงเดียวเป็นอินพุตและส่งคืนอินสแตนซ์ของคลาสเป้าหมาย แต่ไม่ใช่อย่างที่คุณคิด ... พิจารณาคลาสจำนวนเต็ม:
static Integer getInteger(String nm)
Determines the integer value of the system property with the specified name.
วิธีการข้างต้นไม่มีอะไรเกี่ยวข้องกับจำนวนเต็มในฐานะวัตถุที่ห่อหุ้มวัตถุ ints Reflection จะพบว่านี่เป็นตัวเลือกที่เป็นไปได้สำหรับการสร้าง Integer จาก String อย่างไม่ถูกต้องเมื่อเทียบกับ decode, valueof และ constructor Members ซึ่งทั้งหมดนี้เหมาะสำหรับการแปลง String โดยพลการส่วนใหญ่ที่คุณไม่สามารถควบคุมข้อมูลอินพุตของคุณได้ แต่ต้องการ ทราบว่าเป็นไปได้หรือไม่จำนวนเต็ม
ในการแก้ไขข้างต้นการมองหาวิธีการที่ส่งข้อยกเว้นเป็นการเริ่มต้นที่ดีเนื่องจากค่าอินพุตที่ไม่ถูกต้องซึ่งสร้างอินสแตนซ์ของวัตถุดังกล่าวควรทำให้เกิดข้อยกเว้น น่าเสียดายที่การใช้งานแตกต่างกันไปตามการประกาศข้อยกเว้นว่าเลือกไว้หรือไม่ Integer.valueOf (String) พ่น NumberFormatException ที่ตรวจสอบแล้วเช่น แต่ไม่พบข้อยกเว้น Pattern.compile () ในระหว่างการค้นหาการสะท้อน อีกครั้งไม่ใช่ความล้มเหลวของแนวทาง "การหล่อข้ามสาย" แบบไดนามิกนี้ฉันคิดว่ามากเท่ากับการใช้งานที่ไม่ได้มาตรฐานสำหรับการประกาศข้อยกเว้นในวิธีการสร้างวัตถุ
หากใครต้องการรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการใช้งานข้างต้นโปรดแจ้งให้เราทราบ แต่ฉันคิดว่าโซลูชันนี้มีความยืดหยุ่น / ขยายได้มากกว่าและมีรหัสน้อยกว่าโดยไม่สูญเสียส่วนที่ดีของประเภทความปลอดภัย แน่นอนว่าเป็นการดีที่สุดที่จะ "รู้จักข้อมูลของคุณ" แต่อย่างที่หลาย ๆ คนพบว่าบางครั้งเราเป็นเพียงผู้รับเนื้อหาที่ไม่มีการจัดการและต้องพยายามอย่างดีที่สุดเท่าที่จะทำได้เพื่อใช้อย่างเหมาะสม
ไชโย