2012-08-13 9 views
14

अक्सर मैं नेस्टेड .map और .getOrElse के बहुत सारे के साथ खत्म होता है जब कई consecutives स्थितिस्केला शैली - कैसे

उदाहरण के लिए

मान्य नेस्टेड नक्शे के बहुत से बचने के लिए:

def save() = CORSAction { request => 
    request.body.asJson.map { json => 
    json.asOpt[Feature].map { feature => 
     MaxEntitiyValidator.checkMaxEntitiesFeature(feature).map { rs => 
     feature.save.map { feature => 
      Ok(toJson(feature.update).toString) 
     }.getOrElse { 
      BadRequest(toJson(
      Error(status = BAD_REQUEST, message = "Error creating feature entity") 
     )) 
     } 
     }.getOrElse { 
     BadRequest(toJson(
      Error(status = BAD_REQUEST, message = "You have already reached the limit of feature.") 
     )) 
     } 
    }.getOrElse { 
     BadRequest(toJson(
     Error(status = BAD_REQUEST, message = "Invalid feature entity") 
    )) 
    } 
    }.getOrElse { 
    BadRequest(toJson(
     Error(status = BAD_REQUEST, message = "Expecting JSON data") 
    )) 
    } 
} 

आप मिल विचार

मैं बस वहाँ इसे और अधिक स्पष्ट

उत्तर

3

यह जहां एक इकाई का उपयोग कर अपने कोड साफ कर सकते हैं का एक उत्कृष्ट उदाहरण है रखने के लिए कुछ मुहावरेदार तरीका है जानना चाहता था। उदाहरण के लिए आप लिफ्ट के Box का उपयोग कर सकते हैं, जो किसी भी तरह से Lift से जुड़ा हुआ नहीं है।

requestBox.flatMap(asJSON).flatMap(asFeature).flatMap(doSomethingWithFeature) 

जहां asJson एक Box[JSON] और asFeature के लिए एक अनुरोध से एक समारोह है कुछ अन्य Box करने के लिए एक Feature से एक समारोह है: तो फिर अपने कोड कुछ इस तरह दिखेगा। बॉक्स में या तो एक मान हो सकता है, जिस स्थिति में flatMap उस मान के साथ फ़ंक्शन को कॉल करता है, या यह Failure का उदाहरण हो सकता है और उस स्थिति में flatMap उस कार्य को पास नहीं करता है।

यदि आपने कुछ उदाहरण कोड पोस्ट किया था जो संकलित करता है, तो मैं संकलित करता हूं जो एक संकलित पोस्ट कर सकता था।

+0

आपके उत्तर के लिए बहुत बहुत धन्यवाद, मैंने जो कोड पोस्ट किया है, वह संकलित करता है, लेकिन मुझे लगता है कि इस उदाहरण के लिए थोड़ा जटिल है ... – opensas

+2

और विभिन्न स्तरों पर अलग-अलग 'BadRequest' प्रतिक्रियाओं को कैसे बनाए रखता है? ऐसा लगता है कि सीधा-आगे दृष्टिकोण को रोकने में महत्वपूर्ण समस्या है। मैं सोच रहा हूं कि पैटर्न मिलान इस पर निर्भर है? –

+0

यह सही है। एक अनिवार्य भाषा में जैसे ही मुझे कोई त्रुटि मिलती है, मैं बस विधि से बाहर हो जाऊंगा। लेकिन जब मैंने इसे करने की कोशिश की, तो मुझे रिटर्न स्टेटमेंट के साथ कई समस्याओं का सामना करना पड़ा http://stackoverflow.com/questions/11929485/scala-problems-with-return-statement/11929616#11929616 – opensas

10

यदि आपको किसी भी मामले के लिए कोई अलग संदेश नहीं लौटना पड़ा तो यह के लिए के लिए आदर्श उपयोग-मामला होगा। आपके मामले में, शायद आप वैलाइडेशन मोनैड का उपयोग करना चाहते हैं, जैसा कि आप स्कालाज़ में पा सकते हैं। उदाहरण (http://scalaz.github.com/scalaz/scalaz-2.9.0-1-6.0/doc.sxr/scalaz/Validation.scala.html)।

कार्यात्मक प्रोग्रामिंग में, आपको अपवाद नहीं फेंकना चाहिए, लेकिन ऐसे कार्यों को चलो जो असफल हो सकते हैं [ए, बी], जहां सम्मेलन ए विफलता के मामले में परिणाम का प्रकार है और बी परिणाम का प्रकार है सफलता का मामला फिर आप वाम (ए) या दाएं (बी) के खिलाफ दो मामलों को संभालने, पुन: निरीक्षण करने के लिए मैच कर सकते हैं।

आप एक विस्तारित या तो [ए, बी] के रूप में प्रमाणीकरण मोनैड के बारे में सोच सकते हैं जहां सत्यापन के बाद के कार्यों को लागू करना या तो परिणाम उत्पन्न होगा, या निष्पादन श्रृंखला में पहली विफलता होगी।

sealed trait Validation[+E, +A] { 
    import Scalaz._ 

    def map[B](f: A => B): Validation[E, B] = this match { 
    case Success(a) => Success(f(a)) 
    case Failure(e) => Failure(e) 
    } 

    def foreach[U](f: A => U): Unit = this match { 
    case Success(a) => f(a) 
    case Failure(e) => 
    } 

    def flatMap[EE >: E, B](f: A => Validation[EE, B]): Validation[EE, B] = this match { 
    case Success(a) => f(a) 
    case Failure(e) => Failure(e) 
    } 

    def either : Either[E, A] = this match { 
    case Success(a) => Right(a) 
    case Failure(e) => Left(e) 
    } 

    def isSuccess : Boolean = this match { 
    case Success(_) => true 
    case Failure(_) => false 
    } 

    def isFailure : Boolean = !isSuccess 

    def toOption : Option[A] = this match { 
    case Success(a) => Some(a) 
    case Failure(_) => None 
    } 


} 

final case class Success[E, A](a: A) extends Validation[E, A] 
final case class Failure[E, A](e: E) extends Validation[E, A] 

आपका कोड अब तीन सत्यापन परतों में मान्यता इकाई का उपयोग करके पुनर्संशोधित जा सकता है। आप उन्हें निम्नलिखित featureValidation(jsonValidation(request))

3

मैं इस कोशिश की देखने के लिए अगर पैटर्न अनुकूल करने के लिए किसी न किसी प्रकार की पेशकश की मिलान की तरह श्रृंखला

def jsonValidation(request:Request):Validation[BadRequest,String] = request.asJson match { 
    case None => Failure(BadRequest(toJson(
     Error(status = BAD_REQUEST, message = "Expecting JSON data") 
    ) 
    case Some(data) => Success(data) 
} 

def featureValidation(validatedJson:Validation[BadRequest,String]): Validation[BadRequest,Feature] = { 
validatedJson.flatMap { 
    json=> json.asOpt[Feature] match { 
    case Some(feature)=> Success(feature) 
    case None => Failure(BadRequest(toJson(
     Error(status = BAD_REQUEST, message = "Invalid feature entity") 
     ))) 
    } 
} 

}

और फिर: आप मूल रूप से निम्नलिखित की तरह एक मान्यता के साथ अपने नक्शे को प्रतिस्थापित करना चाहिए जमा कोड नमूना (शैली में, यदि शाब्दिक रूप से नहीं) कुछ और सुसंगत करने के लिए।

object MyClass { 

    case class Result(val datum: String) 
    case class Ok(val _datum: String) extends Result(_datum) 
    case class BadRequest(_datum: String) extends Result(_datum) 

    case class A {} 
    case class B(val a: Option[A]) 
    case class C(val b: Option[B]) 
    case class D(val c: Option[C]) 

    def matcher(op: Option[D]) = { 
    (op, 
    op.getOrElse(D(None)).c, 
    op.getOrElse(D(None)).c.getOrElse(C(None)).b, 
    op.getOrElse(D(None)).c.getOrElse(C(None)).b.getOrElse(B(None)).a 
    ) match { 
     case (Some(d), Some(c), Some(b), Some(a)) => Ok("Woo Hoo!") 
     case (Some(d), Some(c), Some(b), None) => BadRequest("Missing A") 
     case (Some(d), Some(c), None, None) => BadRequest("Missing B") 
     case (Some(d), None, None, None) => BadRequest("Missing C") 
     case (None, None, None, None) => BadRequest("Missing D") 
     case _         => BadRequest("Egads") 
    } 
    } 
} 

स्पष्ट रूप से इसे और अधिक बेहतर तरीके से लिखने के तरीके हैं; यह पाठक के लिए एक अभ्यास के रूप में छोड़ दिया गया है।

संबंधित मुद्दे