2014-09-03 4 views
14

सी # IDisposable इंटरफेस के साथ using है। जावा 7+ try के साथ समान कार्यक्षमता और AutoCloseable इंटरफ़ेस है। स्कैला आपको इस मुद्दे पर अपना स्वयं का कार्यान्वयन चुनने देता है।सरल स्काला पैटर्न "का उपयोग कर/कोशिश-संसाधनों के साथ" (स्वचालित संसाधन प्रबंधन)

स्केला हाथ के लोकप्रिय विकल्प हो रहा है, और typesafe कर्मचारियों में से एक द्वारा बनाए रखा है। हालांकि, यह इतना आसान व्यवहार के लिए बहुत जटिल लगता है। स्पष्ट करने के लिए उपयोग निर्देश आसान है, लेकिन कैसे समझ कि सभी कोड आंतरिक रूप से काम कर रहा है बल्कि जटिल है।

मैं सिर्फ निम्नलिखित सुपर सरल एआरएम समाधान लिखा है:

object SimpleARM { 
    def apply[T, Q](c: T {def close(): Unit})(f: (T) => Q): Q = { 
    try { 
     f(c) 
    } finally { 
     c.close() 
    } 
    } 
} 
  • वहाँ सरल हाथ की तरह कुछ करने के लिए कोई लाभ है? ऐसा लगता है कि सभी अतिरिक्त जटिलताओं को अतिरिक्त लाभ प्रदान करना चाहिए।
  • आम तौर पर, सार्वजनिक कोड, ओपन सोर्स, लाइब्रेरी का उपयोग करना बेहद बेहतर है जो कस्टम कोड का उपयोग करने पर सामान्य उद्देश्य व्यवहार के लिए दूसरों द्वारा समर्थित है।
  • किसी को भी किसी भी सुधार की सिफारिश कर सकते हैं?
  • क्या इस सरल दृष्टिकोण के लिए कोई सीमाएं हैं?
+0

AFAIK, "सी" के प्रकार के प्रतिबिंब के आधार पर किया जाता है, प्रदर्शन के मामले में समस्याग्रस्त किया जा सकता है जो और जब पुनर्रचना या Bytecode कहानियो का उपयोग कर। इसके बजाए, मैं बस java.lang.AutoCloseable प्रकार का पुन: उपयोग करूंगा। –

+0

आपका कोड 'c' == शून्य केस संभाल नहीं करता है। और यह अस्पष्ट है कि अगर बंद() एक अपवाद फेंकता है तो कौन सा अपवाद फेंक दिया जाएगा। –

+0

क्योंकि मुझे कई java.lang.AutoCloseable उदाहरणों को घोंसला करने में सक्षम होना चाहिए, जिनमें से प्रत्येक पहले सफलतापूर्वक तत्काल तत्काल पर निर्भर करता है, अंत में मैंने एक पैटर्न पर मारा जो मेरे लिए बहुत उपयोगी रहा है। stackoverflow.com/a/34277491/501113 – chaotic3quilibrium

उत्तर

4

यहाँ मेरी नई सरल है समर्थन एक नज़र, स्काला एआरएम पर समझने के लिए विफल रहता है। यह प्रत्येक उपयोग मामले का पूरी तरह से समर्थन करता है जिसे मैं कई संसाधनों और उपज मूल्यों के बारे में सोच सकता हूं। यह समझ उपयोग वाक्य रचना के लिए एक बहुत ही सरल उपयोग करता है:

class AutoCloseableWrapper[A <: AutoCloseable](protected val c: A) { 
    def map[B](f: (A) => B): B = { 
    try { 
     f(c) 
    } finally { 
     c.close() 
    } 
    } 

    def foreach(f: (A) => Unit): Unit = map(f) 

    // Not a proper flatMap. 
    def flatMap[B](f: (A) => B): B = map(f) 

    // Hack :)  
    def withFilter(f: (A) => Boolean) = this 
} 

object Arm { 
    def apply[A <: AutoCloseable](c: A) = new AutoCloseableWrapper(c) 
} 

यहाँ डेमो फायदा नहीं है:

class DemoCloseable(val s: String) extends AutoCloseable { 
    var closed = false 
    println(s"DemoCloseable create ${s}") 

    override def close(): Unit = { 
    println(s"DemoCloseable close ${s} previously closed=${closed}") 
    closed = true 
    } 
} 

object DemoCloseable { 
    def unapply(dc: DemoCloseable): Option[(String)] = Some(dc.s) 
} 

object Demo { 
    def main(args: Array[String]): Unit = { 
    for (v <- Arm(new DemoCloseable("abc"))) { 
     println(s"Using closeable ${v.s}") 
    } 

    for (a <- Arm(new DemoCloseable("a123")); 
     b <- Arm(new DemoCloseable("b123")); 
     c <- Arm(new DemoCloseable("c123"))) { 
     println(s"Using multiple resources for comprehension. a.s=${a.s}. b.s=${b.s}. c.s=${c.s}") 
    } 

    val yieldInt = for (v <- Arm(new DemoCloseable("abc"))) yield 123 
    println(s"yieldInt = $yieldInt") 

    val yieldString = for (DemoCloseable(s) <- Arm(new DemoCloseable("abc")); c <- s) yield c 
    println(s"yieldString = $yieldString") 

    println("done") 
    } 
} 
+0

मैं लोगों कि एक प्रतिक्रिया unvote और व्याख्या नहीं करते क्यों पसंद नहीं है। – angelcervera

+0

आपका समाधान ओओपी हैक का विशेष रूप से बहुत अधिक है, विशेष रूप से ऑटोक्लोसेबलवापर। मैं जो समाधान प्रदान करता हूं वह जावा एआरएम मॉडल के मूल लाभ को बनाए रखने के दौरान एफपी और अपरिवर्तनीयता के स्कैला मौलिक लक्ष्यों के साथ बहुत अधिक गठबंधन है, सभी एक ही समारोह में दो (करीइंग) पैरामीटर सूचियों के साथ: https://stackoverflow.com/a/ 34277491/501113 – chaotic3quilibrium

11

एक साधारण ऋण पैटर्न के साथ आपका दृष्टिकोण तब तक ठीक काम कर रहा है जब तक आपको कई संसाधनों के साथ काम करने की आवश्यकता नहीं है, सभी को प्रबंधित करने की आवश्यकता है। स्केल-बांह मोनैडिक दृष्टिकोण के साथ इसकी अनुमति है। स्केला हाथ में पता करने के लिए

import resource.managed 

managed(openResA).and(managed(openResB)) acquireFor { (a, b) => ??? } 

val res = for { 
    a <- managed(openResA) 
    b <- managed(openResB) 
    c <- managed(openResC) 
} yield (a, b, c) 

res acquireAndGet { 
    case (a, b, c) => ??? 
} 

मुख्य कार्यों resource.managed और .acquired{For,AndGet}, वास्तव में जटिल नहीं btw है।

+2

एआरएम ने http://stackoverflow.com/questions/8865754/ पर भी उल्लेख किया है, लेकिन परियोजना को कुछ हद तक पुनर्जीवित किया गया था, भले ही यह किसी की परियोजनाओं में शामिल होने के लिए पर्याप्त विश्वसनीय है, स्पष्ट नहीं है। "इनक्यूबेटर" स्थिति के बजाय RTL में विलय में तो कई वर्षों ... –

3

इस कोड मैं का उपयोग करें:

def use[A <: { def close(): Unit }, B](resource: A)(code: A ⇒ B): B = 
    try 
     code(resource) 
    finally 
     resource.close() 

जावा के विपरीत कोशिश-साथ-संसाधन, संसाधन को AutoCloseable लागू करने की आवश्यकता नहीं है। केवल close() विधि आवश्यक है। यह केवल एक ही संसाधन का समर्थन करता है।

val path = Paths get "/etc/myfile" 
use(Files.newInputStream(path)) { inputStream ⇒ 
    val firstByte = inputStream.read() 
    .... 
} 
+1

आपका समाधान निस्संदेह प्रतिबिंब पर निर्भर करता है। हां, बतख टाइपिंग, जो आप उपयोग कर रहे हैं, केवल प्रतिबिंब के माध्यम से उपलब्ध है। तो, इसका मतलब है कि आपका समाधान Scala.js या ScalaNative जैसे स्थानों पर सामान्य नहीं है। – chaotic3quilibrium

+0

मुझे लगता है कि यह रनटाइम प्रतिबिंब का उपयोग नहीं करता है। –

+1

और यह आपको अवगत करवाने के आप इस बारे में क्या सोचते के लिए समय है: https://stackoverflow.com/a/8539585/501113 – chaotic3quilibrium

1

यह एक मेरे लिए काम करता वास्तव में अच्छी तरह:

implicit class ManagedCloseable[C <: AutoCloseable](resource: C) { 
    def apply[T](block: (C) => T): T = { 
    try { 
     block(resource) 
    } finally { 
     resource.close() 
    } 
    } 

इस अपाचे कैसेंड्रा ग्राहक कोड में उदाहरण के लिए इसे प्रयोग:

val metadata = Cluster.builder().addContactPoint("vader").withPort(1234).build() { cluster => 
    cluster.getMetadata 
} 

यहाँ एक InputStream साथ एक उदाहरण इस्तेमाल होता है

या भी कम:

val metadata = Cluster.builder().addContactPoint("sedev01").withPort(9999).build()(_.getMetadata) 
0

एक सुधार मैं दृष्टिकोण आप का सुझाव दिया है, जो करने के लिए सिफारिश कर सकते हैं:

def autoClose[A <: AutoCloseable, B](resource: A)(code: A ⇒ B): B = { 
    try 
     code(resource) 
    finally 
     resource.close() 
    } 

उपयोग करने के लिए है:

def autoClose[A <: AutoCloseable, B](resource: A)(code: A ⇒ B): Try[B] = { 
    val tryResult = Try {code(resource)} 
    resource.close() 
    tryResult 
    } 

IMHO tryResult जो एक Try[B] होती है, फिर अनुमति देगा आप एक बाद में आसान नियंत्रण प्रवाह।

1

अस्थिर के लेज़ी TryClose इकाई हो सकता है आप के लिए क्या देख रहे हैं। यह स्कैला के प्रयास के समान ही है लेकिन स्वचालित रूप से संसाधनों को स्वचालित रूप से बंद कर देता है।

val ds = new JdbcDataSource() 
val output = for { 
    conn <- TryClose(ds.getConnection()) 
    ps <- TryClose(conn.prepareStatement("select * from MyTable")) 
    rs <- TryClose.wrap(ps.executeQuery()) 
} yield wrap(extractResult(rs)) 

// Note that Nothing will actually be done until 'resolve' is called 
output.resolve match { 
    case Success(result) => // Do something 
    case Failure(e) =>  // Handle Stuff 
} 

अधिक जानकारी के लिए देखें: https://github.com/choppythelumberjack/tryclose

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