2013-01-23 34 views
37

क्या मेरे कस्टम अपवाद प्रकार case class es होना चाहिए?क्या अपवाद केस कक्षाएं होनी चाहिए?

प्लस तरफ, मुझे निकालने वाले मिलते हैं।

कम से कम, मुझे गलत समानता अर्थशास्त्र मिलता है। लेकिन मैं equals ओवरराइड करके इससे बच सकता हूं।

तो क्या यह case class es बनाने के लिए, एक वैचारिक स्तर पर, यह समझ में आता है?

+6

@TravisBrown - "कुछ भी मैं मुझे लगता है कि मुझे पता होना चाहिए कि यह स्पष्ट होना चाहिए और इसलिए रचनात्मक नहीं है। " –

+0

जो मैं खोज रहा हूं वह एक मैक्रो होगा जो लागू और अनुपयोगी के साथ साथी की तरह केस-क्लास बनाता है, लेकिन बाकी सब कुछ के बिना, खासकर विरासत प्रतिबंधों के बिना। यह अन्य स्थानों में भी उपयोगी होगा। –

उत्तर

32

यह निश्चित रूप से बहुत ही व्यक्तिपरक है, लेकिन मेरी राय में यह कक्षाओं के रूप में अपवाद वर्गों के लिए अच्छा अभ्यास है। मुख्य तर्क यह है कि जब आप अपवाद प्राप्त करते हैं, तो आप पैटर्न मिलान कर रहे हैं, और केस क्लास पैटर्न मिलान में उपयोग करने के लिए बहुत अच्छे हैं। यहाँ एक उदाहरण है कि एक कैच ब्लॉक, में पैटर्न मिलान का संपूर्ण उपयोग करने की क्षमता की advantadge जब एक मामले वर्ग अपवाद का उपयोग कर ले जाता है:

object IOErrorType extends Enumeration { 
    val FileNotFound, DeviceError, LockedFile = Value 
} 
case class IOError(message: String, errorType: IOErrorType.Value) extends Exception(message) 

def doSomeIO() { throw IOError("Oops, file not found!", IOErrorType.FileNotFound) } 

try { 
    doSomeIO() 
} catch { 
    case IOError(msg, IOErrorType.FileNotFound) => 
    println("File not found, please check the path! (" + msg + ")") 
} 

इस उदाहरण में, हम केवल एक अपवाद है, लेकिन यह होता है एक errorType फ़ील्ड जब आप सटीक त्रुटि प्रकार को जानना चाहते हैं (आमतौर पर इसे अपवाद के पदानुक्रम के माध्यम से मॉडलिंग किया जाता है, तो मैं यह नहीं कह रहा हूं कि यह बेहतर या बदतर है, उदाहरण केवल चित्रकारी है)। क्योंकि IOError एक केस क्लास है, मैं केवल त्रुटि के लिए अपवाद को पकड़ने के लिए case IOError(msg, IOErrorType.FileNotFound) कर सकता हूं। एक्स्ट्रेक्टरों के बिना जो हम कक्षा वर्गों के साथ मुफ्त में आते हैं, मुझे हर बार अपवाद पकड़ना होगा, और फिर यदि मैं वास्तव में दिलचस्पी नहीं लेता हूं तो फिर से प्रयास करें, जो निश्चित रूप से अधिक वर्बोज़ है।

आप कहते हैं कि केस कक्षाएं आपको गलत समानता अर्थशास्त्र देती हैं। मुझे ऐसा नहीं लगता। आप, अपवाद वर्ग के लेखक के रूप में यह तय करने के लिए मिलता है कि समानता अर्थशास्त्र समझ में आता है। जब आप अपवाद प्राप्त करते हैं, तो कैच ब्लॉक वह जगह है जहां आप निर्णय लेते हैं कि आम तौर पर अकेले प्रकार के आधार पर पकड़ने के लिए कौन से अपवाद हैं, लेकिन मेरे उदाहरण के अनुसार, जो इसके खेतों या जो कुछ भी हो, उसके आधार पर हो सकता है। मुद्दा यह है कि अपवाद वर्ग की समानता अर्थशास्त्र के साथ इसका कोई संबंध नहीं है।

17

अपवाद केस कक्षाओं द्वारा खोने वाला एक सामान्य मुहावरे त्रुटि वर्ग की अधिक विशिष्टता को इंगित करने के लिए उपयोग किए गए सबक्लासिंग के साथ अपवादों के उप-वर्ग पदानुक्रम बनाने का पैटर्न है। केस कक्षाओं को उपclassed नहीं किया जा सकता है।

+3

अच्छा बिंदु। लेकिन यदि आवश्यक हो तो भी आप अमूर्त अपवाद प्रकारों (लक्षणों या सार वर्गों) का पदानुक्रम बना सकते हैं और सभी पत्ते के प्रकार केस कक्षाएं हो सकते हैं। इसके लिए आपको पूरे पदानुक्रम की "आवश्यकता" है, या दूसरे शब्दों में कि क्लाइंट कोड आपके अपवाद वर्गों को विस्तारित नहीं करना चाहता है। यदि ऐसा नहीं है तो अपवादों के लिए केस क्लास का उपयोग करना वास्तव में सबसे अच्छा विचार नहीं हो सकता है। –

+2

हालांकि आप एक सामान्य विशेषता –

+3

केस कक्षाओं को उप-वर्गीकृत कर सकते हैं। केवल प्रतिबंध यह है कि सबक्लास एक केस क्लास नहीं हो सकता है। –

1

मुझे रेगिस जीन-गिल्स से उत्तर पसंद है। लेकिन अगर आप एक अच्छे कारण के एक मामले वर्ग नहीं किया है (डेव ग्रिफ़िथ के जवाब देखें), आप एक सामान्य वर्ग और unapply ऊपर दिए उदाहरण में के रूप में ही archieve कर सकते हैं:

object IOErrorType extends Enumeration { 
    val FileNotFound, DeviceError, LockedFile = Value 
} 
object IOError { 
    def unapply(err: IOError): Option[(String, IOErrorType.Value)] = Some(err.message, err.errorType) 
} 
class IOError(val message: String, val errorType: IOErrorType.Value) extends Exception(message) 

def doSomeIO() { throw new IOError("Oops, file not found!", IOErrorType.FileNotFound) } 

try { 
    doSomeIO() 
} catch { 
    case IOError(msg, IOErrorType.FileNotFound) => 
    println("File not found, please check the path! (" + msg + ")") 
}