ฉันเพิ่งพูดคุยเกี่ยวกับตัวเลือกการออกแบบหลังจากการตรวจสอบโค้ด ฉันสงสัยว่าความคิดเห็นของคุณคืออะไร
มีPreferences
คลาสนี้ซึ่งเป็นที่เก็บข้อมูลสำหรับคู่คีย์ - ค่า ค่า Null นั้นถูกกฎหมาย (สำคัญมาก) เราคาดหวังว่าค่าบางอย่างอาจยังไม่ถูกบันทึกและเราต้องการจัดการกับกรณีเหล่านี้โดยอัตโนมัติโดยเริ่มต้นด้วยค่าเริ่มต้นที่กำหนดไว้ล่วงหน้าเมื่อมีการร้องขอ
วิธีแก้ปัญหาที่กล่าวถึงใช้รูปแบบต่อไปนี้ (หมายเหตุ: นี่ไม่ใช่รหัสจริงแน่นอน - มันง่ายสำหรับจุดประสงค์ในการอธิบาย):
public class Preferences {
// null values are legal
private Map<String, String> valuesFromDatabase;
private static Map<String, String> defaultValues;
class KeyNotFoundException extends Exception {
}
public String getByKey(String key) {
try {
return getValueByKey(key);
} catch (KeyNotFoundException e) {
String defaultValue = defaultValues.get(key);
valuesFromDatabase.put(key, defaultvalue);
return defaultValue;
}
}
private String getValueByKey(String key) throws KeyNotFoundException {
if (valuesFromDatabase.containsKey(key)) {
return valuesFromDatabase.get(key);
} else {
throw new KeyNotFoundException();
}
}
}
มันได้รับการวิพากษ์วิจารณ์ว่าการต่อต้านรูปแบบ - เหยียดหยามข้อยกเว้นในการควบคุมการไหล KeyNotFoundException
- นำมาสู่ชีวิตสำหรับกรณีการใช้งานเพียงอย่างเดียวเท่านั้น - จะไม่ปรากฏให้เห็นนอกขอบเขตของคลาสนี้
โดยพื้นฐานแล้วมันมีวิธีการสองอย่างที่จะดึงเอามาใช้เพื่อสื่อสารกัน
กุญแจที่ไม่มีอยู่ในฐานข้อมูลไม่ใช่สิ่งที่น่าตกใจหรือเป็นข้อยกเว้นเราคาดว่าสิ่งนี้จะเกิดขึ้นทุกครั้งที่มีการเพิ่มการตั้งค่าการกำหนดค่าตามความชอบใหม่ดังนั้นกลไกที่เริ่มต้นได้อย่างสง่างามด้วยค่าเริ่มต้นหากจำเป็น
การโต้เถียงคือgetValueByKey
- วิธีส่วนตัว - ตามที่นิยามไว้ในขณะนี้ไม่มีวิธีที่เป็นธรรมชาติในการแจ้งวิธีสาธารณะเกี่ยวกับทั้งค่าและคีย์อยู่ที่นั่นหรือไม่ (หากไม่มีจะต้องเพิ่มเพื่อให้สามารถอัปเดตค่าได้)
กลับมาnull
จะไม่ชัดเจนเนื่องจากเป็นค่าที่สมบูรณ์ตามกฎหมายเพื่อให้มีไม่มีบอกว่ามันหมายความว่าที่สำคัญไม่ได้มีหรือถ้ามีnull
null
getValueByKey
จะต้องกลับมาบางจัดเรียงของTuple<Boolean, String>
, บูลที่กำหนดให้เป็นจริงถ้าคีย์มีอยู่แล้วเพื่อให้เราสามารถแยกแยะความแตกต่างระหว่างและ(true, null)
(false, null)
( out
พารามิเตอร์สามารถใช้ใน C # แต่นั่นคือ Java)
นี่เป็นทางเลือกที่ดีกว่าไหม? ใช่คุณต้องกำหนดคลาสแบบใช้ครั้งเดียวบางส่วนเพื่อให้ได้ผลTuple<Boolean, String>
แต่แล้วเราก็จะถูกกำจัดKeyNotFoundException
เพื่อให้เกิดความสมดุลดังกล่าว นอกจากนี้เรายังหลีกเลี่ยงค่าใช้จ่ายในการจัดการข้อยกเว้นแม้ว่าจะไม่ได้มีนัยสำคัญในแง่การปฏิบัติ - ไม่มีการพิจารณาประสิทธิภาพที่จะพูดถึงมันเป็นแอปไคลเอนต์และไม่ชอบการตั้งค่าผู้ใช้จะถูกเรียกล้านครั้งต่อวินาที
รูปแบบของวิธีการนี้สามารถใช้ฝรั่งของOptional<String>
(ฝรั่งถูกใช้ไปแล้วตลอดโครงการ) แทนกำหนดเองบางส่วนTuple<Boolean, String>
และจากนั้นเราสามารถแยกความแตกต่างระหว่างOptional.<String>absent()
และ null
"เหมาะสม" แต่ก็ยังรู้สึกแฮ็กด้วยเหตุผลที่มองเห็นได้ง่าย - การแนะนำ "ความไร้ค่า" สองระดับดูเหมือนจะเป็นการละเมิดแนวคิดที่ยืนอยู่ข้างหลังการสร้างOptional
ในตอนแรก
อีกทางเลือกหนึ่งคือการตรวจสอบอย่างชัดเจนว่ามีคีย์อยู่หรือไม่ (เพิ่มboolean containsKey(String key)
เมธอดและเรียกgetValueByKey
เฉพาะเมื่อเรายืนยันแล้วว่ามีอยู่)
ในที่สุดก็สามารถอินไลน์วิธีส่วนตัว แต่จริงgetByKey
ๆ แล้วค่อนข้างซับซ้อนกว่าตัวอย่างรหัสของฉันดังนั้นการทำอินไลน์จะทำให้มันดูน่ารังเกียจทีเดียว
ฉันอาจแยกเส้นขนที่นี่ แต่ฉันอยากรู้ว่าสิ่งที่คุณจะวางเดิมพันใกล้เคียงกับแนวปฏิบัติที่ดีที่สุดในกรณีนี้ ฉันไม่พบคำตอบในคำแนะนำสไตล์ของ Oracle หรือ Google
การใช้ข้อยกเว้นเช่นในตัวอย่างโค้ดเป็นการต่อต้านรูปแบบหรือเป็นที่ยอมรับเนื่องจากตัวเลือกอื่นไม่สะอาดมากใช่ไหม ถ้าเป็นภายใต้สถานการณ์เช่นนั้นมันจะดีไหม? และในทางกลับกัน?
getValueByKey
เป็นสาธารณะ