2012-06-25 32 views
6

मैं आरईएसटी एपीआई से प्रतिक्रियाओं को मॉडल करने का प्रयास कर रहा हूं क्योंकि कक्षाओं के साथ मैं पैटर्न मिलान का उपयोग कर सकता हूं।स्कैला केस क्लास के साथ मॉडलिंग

मैंने सोचा कि यह विरासत मानने के लिए एक अच्छा फिट होगा, लेकिन मुझे लगता है कि यह बहिष्कृत है। मुझे पता है कि केस कक्षाओं और विरासत से संबंधित प्रश्न पहले से ही हैं, लेकिन मेरा प्रश्न इस बारे में अधिक है कि आप के बिना विरासत के "सही तरीके" का मॉडल कैसे करेंगे। से REST कॉल यानी

case class Body(contentType: String, content: String) 
case class Response(statusCode: Int, body: Body) 

की तरह कुछ के साथ वापसी होगी:

Response(200, Body("application/json", """{ "foo": "bar" }""")) 

जो मैं कर सकता पैटर्न मैच की तरह:

मैं निम्नलिखित दो मामले कक्षाएं, जो ठीक से काम के साथ शुरू

response match { 
    case Response(200, Body("application/json", json)) => println(json) 
    case Response(200, Body("text/xml", xml)) => println(xml) 
    case Response(_,_) => println("Something unexpected") 
} 

आदि जो ठीक काम करता है।

कहाँ मैं मुसीबत में भाग गया है:

response match { 
    case OK(JSON(json)) => println(json) 
    case OK(XML(xml)) => println(xml) 
    case NotFound() => println("Something is not there") 

    // And still drop down to this if necessary: 
    case Response(302, _) => println("It moved") 
} 

:

case class OK(body: Body) extends Response(200, body) 
case class NotFound() extends Response(404, Body("text/plain", "Not Found")) 

case class JSON(json: String) extends Body("application/json", json) 
case class XML(xml: String) extends Body("text/xml", xml) 
तो मैं सरलीकृत कर सकते हैं कि पैटर्न इस तरह से मेल खाता है

: मैं इस तरह के रूप में इन मामले कक्षाओं के लिए सहायक एक्सटेंशन, चाहते हैं और यह भी मेरे आरईएसटी कोड को सीधे उपयोग करने और वापस करने की अनुमति देगा:

Response(code, Body(contentType, content)) 

जो ई है गतिशील रूप से एक प्रतिक्रिया बनाने के लिए asier।

case class OK(override val body: Body) extends Response(200, body) 

हालांकि, इस पैटर्न मिलान के साथ काम नहीं लगता है:

के माध्यम से

तो ...

मैं इसे (प्रतिवाद चेतावनी के साथ) संकलित करने के लिए मिल सकता है।

Response(200, Body("application/json", "")) match { 
    case OK(_) => ":-)" 
    case _ => ":-(" 
} 
res0: java.lang.String = :-(

यह कैसे काम कर सकता है इस पर कोई विचार? मैं अलग-अलग दृष्टिकोणों के लिए खुला हूं, लेकिन यह केस कक्षा

उत्तर

10

के लिए व्यावहारिक उपयोग खोजने का मेरा प्रयास था, केस क्लास shouldn't be subclassed क्यों कई कारण हैं। आपके मामले में, समस्या यह हो जाती है कि OKResponse से एक अन्य प्रकार (उप प्रकार का) है, इसलिए मिलान विफल रहता है (भले ही तर्क मिलान हो, प्रकार मेल नहीं खाता है)।

आप इसके बजाय custom extractors चाहते हैं। उदाहरण के लिए:

case class Response(code: Int, body: String) 
object OK { 
    def apply(body: String) = Response(200, body) 
    def unapply(m: Response): Option[String] = m match { 
    case Response(200, body) => Some(body) 
    case _     => None 
    } 
} 

def test(m: Response): String = m match { 
    case OK(_) => ":-)" 
    case _  => ":-(" 
} 

test(Response(300, "Hallo")) // :-(
test(Response(200, "Welt")) // :-) 
test(OK("Welt"))    // :-) 

this thread में कस्टम एक्सट्रैक्टर्स के कुछ और उदाहरण हैं।

+0

आह, धन्यवाद - मुझे लगता है कि मैंने इसे पूरी तरह से अनुपयोगी के उद्देश्य को याद किया है; यह बहुत उपयोगी है। यह सुनिश्चित करने के लिए कि मैंने आज रात को कवर किया है और स्वीकार करूँगा, यह सुनिश्चित करने के लिए मेरे कोड के साथ पूरी तरह से इसका परीक्षण करेगा। – 7zark7

+0

अच्छा जवाब @ एससीआईएस। कस्टम एक्स्ट्रेक्टर्स उन चीज़ों में से एक हैं जिन्हें मुझे स्कैला के बारे में बहुत पसंद है। – mergeconflict

+0

@ 7zark7 ध्यान दें कि जब आप कस्टम निकालने वाले का उपयोग करते हैं तो आप सीलबंद कक्षाओं की थकावट गारंटी खो देते हैं। –

1

क्या आपने स्कैला लाइब्रेरी को फ़िल्टर किया है? http://unfiltered.lessis.me/ यह आपको समस्या के साथ आने में आपकी मदद कर सकता है। एचटीएच

+0

मैंने एक नज़र डाली लेकिन मैंने छोड़ दिया क्योंकि बहुत से स्लाइड थे, प्रत्येक पर 1 वाक्य/कुछ-शब्द। क्या शायद कोई भी पृष्ठ संस्करण है जो स्पष्ट करता है कि अनफिल्टर क्या है? – KajMagnus

+0

यह एक बेहतर काम करने में मदद कर सकता है: https://github.com/softprops/Unfiltered – AndreasScheinert

1

जबकि 0__ द्वारा वर्णित कस्टम निकालने वाले निश्चित रूप से उपयोग किए जा सकते हैं, तो आप सीलबंद प्रकार पदानुक्रमों की थकावट गारंटी खो देंगे। उदाहरण के दौरान आपने प्रश्न में दिया है sealed कुछ भी नहीं है, समस्या उनके लिए उपयुक्त है।

उस मामले में, मेरा सुझाव यह सुनिश्चित करना है कि case class हमेशा टाइप पदानुक्रम के नीचे है, और ऊपरी कक्षाओं को सामान्य बनाते हैं। उदाहरण के लिए:

sealed class Response(val statusCode: Int, val body: Body) sealed 
case class Ok(override val body: Body) extends Response(200, body) 
sealed class NotOk(statusCode: Int, body: Body) extends Response(statusCode, body) 
case object NotFound extends NotOk(404, "Not found") 
// and so on... 
+0

धन्यवाद डैनियल, जबकि मेरी पहली छाप यह काम नहीं करेगी अगर मैं प्रतिक्रिया पर मैचों की अनुमति देना चाहता था - मुझे लगता है कि अगर मैं परिभाषित करता हूं तो यह काम कर सकता है एक प्रतिक्रिया वस्तु पर अनुपयोगी के रूप में स्विस का उल्लेख है, और "सहायक" मामले कक्षाएं हैं। आज दोनों दृष्टिकोणों को आजमाएं और देखें कि यहां कौन सा फिट/काम करता है। – 7zark7

+0

क्या आप 'मुहरबंद वर्ग प्रतिक्रिया' लिखना चाहते थे? –

+0

@ स्विस हां, और 'नोटोक' भी। मेरी गलती को इंगित करने के लिए धन्यवाद। –