2012-03-03 15 views
9

में एक मौजूदा जावा वर्ग के लिए एक कारखाने विधि कैसे जोड़ें एक शुद्ध स्काला वातावरण में, मैं अगर मैं करने के लिए किसी मौजूदा ऑब्जेक्ट को एक कारखाने विधि "जोड़ें" चाहता था निम्नलिखित कर सकता है मौजूदा जावा क्लास के साथ संयोजन में ऐसी कार्यक्षमता की आवश्यकता होगी। मेरे ठोस उदाहरण में, मैं कक्षा com.google.android.maps.GeoPoint पर फ़ैक्टरी विधि fromLocation जोड़ना चाहूंगा (और मुझे लगता है कि प्रत्येक एंड्रॉइड डेवलपर को यह पता चलेगा कि यह उपयोगी क्यों होगा ;-))।स्काला

हालांकि, अगर मैं की तरह

implicit def fromGeoPoint(t: GeoPoint.type) = RichTest 

मैं बताते हुए

प्रकार मेल नहीं खाता कोई त्रुटि मिलती है कुछ करने की कोशिश; पाया: com.google.android.maps.GeoPoint.type (अंतर्निहित प्रकार वस्तु com.google.android.maps.GeoPoint साथ) की आवश्यकता: AnyRef

तो मुझे आश्चर्य है कि अगर वहाँ किसी भी तरह से कैसे ऊपर दृष्टिकोण सकता है कार्यान्वित किया जा सकता है - या Location से GeoPoint तक एक अंतर्निहित रूपांतरण प्रदान करेगा, स्केल में पसंदीदा तरीका होना चाहिए ताकि Location का उपयोग किया जा सके जब भी GeoPoint आवश्यक हो?


, टिप्पणी में अनुरोध के रूप में एक उपयोग परिदृश्य:

// Callback you get from the GPS 
override def onLocationChanged(l: Location) { 
    // You want to put a marker on a map, hence a GeoPoint is required 
    val gp: GeoPoint = GeoPoint.fromLocation(location) 
    val item = new OverlayItem(gp, ...) 
    .... 
} 

हालांकि, यह ध्यान रखें कि यह सिर्फ एक सामान्य समस्या ;-)

+0

क्या आप इस फैक्ट्री विधि का उपयोग करने वाले कोड का उदाहरण दे सकते हैं? उदाहरण के लिए, भू-बिंदु और स्थान के साथ। मैं वास्तव में इस सवाल को समझ नहीं पा रहा हूं। – Fixpoint

+0

@ फ़िक्सपॉइंट किया गया ;-) – Leo

उत्तर

2

की स्काला संस्करण यह 2.9.1 के रूप में संभव नहीं है फैक्टरी विधि के साथ जावा क्लास का विस्तार करें।

  1. लिखें Scala compiler plugin आवश्यक परिवर्तनों को समायोजित और फिर जावा वर्ग का विस्तार करने के:

    हालांकि, वहाँ तीन वैकल्पिक समाधान कर रहे हैं।

  2. एक स्टैंडअलोन फैक्ट्री विधि बनाएं।
  3. फैक्ट्री विधि का पूरी तरह से उपयोग करने से बचें और एक अंतर्निहित रूपांतरण जोड़ें ताकि स्थान वस्तु का उपयोग हमेशा भू-बिंदु के स्थान पर किया जा सके।

व्यक्तिगत तौर पर मैं तीसरे विकल्प के लिए अगर मैं Location इस्तेमाल किया जाना चाहते हैं ->GeoPoint या किसी अन्य रूपांतरण बहुत समय, विशेष रूप से परिदृश्य में जब रूपांतरण हमेशा अपवाद और वर्ग इंटरफेस बिना किया जा सकता नहीं है ओवरलैप।

implicit def geoPointFromLocation(l: Location):GeoPoint = new GeoPoint... 

override def onLocationChanged(l: Location) {   
    val gp: GeoPoint = l // let Scala compiler do the conversion for you 
    val item = new OverlayItem(gp, ...) 
    .... 
    // or just pass the location to OverlayItem constructor directly 
    val item2 = new OverlayItem(l, ...) 
} 
0

आप क्या चाहते हैं के लिए विशिष्ट उदाहरण है करना असंभव है। चूंकि जावा क्लास स्कैला ऑब्जेक्ट नहीं है क्योंकि इसे विधियों के साथ विस्तारित करने का कोई तरीका नहीं है।

केवल बिंदु मैं यथासंभव आसान काम करने के लिए देख स्काला में एक वस्तु बना सकते हैं और जावा वर्ग के लिए एक योग्य आयात बनाना है:

import test.{ Test => JTest } 
object Test { 
    def anyMethodHere ... 
} 
+0

... जो बिल्कुल मैं नहीं चाहता हूं। जावा में एक कारखाना विधि एक स्थिर विधि है; स्कैला बराबर ऑब्जेक्ट विधियां हैं, है ना? मैं स्कैला में स्थिर जावा विधियों को कॉल कर सकता हूं, इसलिए किसी प्रकार का स्थैतिक-टू-ऑब्जेक्ट रूपांतरण होना चाहिए। अंत में, मैं स्कैला के माध्यम से जावा क्लास में एक स्थिर विधि जोड़ना चाहता हूं। जिसका अर्थ है कि नया-कीवर्ड वह चीज़ है जिसे मैं नहीं चाहता हूं। – Leo

+0

@Mef: मुझे खेद है कि मैं उस बिंदु से चूक गया। मैंने अपना जवाब अपडेट किया, भले ही मैं वास्तव में आपकी मदद नहीं कर सकता। – sschaef

2

महान प्रश्न! दुर्भाग्यवश, मुझे नहीं लगता कि यह संभव है। चूंकि जावा में किसी वर्ग के स्थिर हिस्सों को मूल्य के रूप में उपयोग करने का कोई तरीका नहीं है, इसलिए जावा क्लास के स्थिर सदस्यों के प्रकार AnyRef को बढ़ाने के लिए कोई कारण नहीं है। और दुर्भाग्य से, जावा ऑब्जेक्ट को किसी भी आरईएफ को विस्तारित करने के लिए आप अंतर्निहित रूपांतरण का उपयोग करेंगे, जिसके लिए जावा ऑब्जेक्ट को किसी भी आरईएफ को बढ़ाने की आवश्यकता है ...

हालांकि मुझे गलत साबित होना अच्छा लगेगा!

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

अद्यतन: यहां जावा और स्कैला (क्या डारियो वर्णन कर रहा था) के बीच अंतर का एक पूर्ण उदाहरण है।

# vim Test.java 
class Test { 
    public static final int foo = 1; 
    public final int bar = 2; 
} 

# javac Test.java 
# ls 

Test.class Test.java 

# javap Test 

Compiled from "Test.java" 
class Test { 
    public static final int foo; 
    public final int bar; 
    Test(); 
} 

की तुलना में, स्केला के साथ:

# vim Test.scala 

object Test { 
    val foo = 1 
} 

class Test { 
    val bar = 2 
} 

# javac Test.scala 
# ls 

Test$.class Test.class Test.scala 

# javap Test 

public class Test implements scala.ScalaObject { 
    public static final int foo(); 
    public int bar(); 
    public Test(); 
} 

# javap Test$ 

Compiled from "Test.scala" 
public final class Test$ implements scala.ScalaObject { 
    public static final Test$ MODULE$; 
    public static {}; 
    public int foo(); 
} 
2

इसका कारण यह है object ... पर स्केला में एक सिंगलटन उदाहरण जावा वर्ग में स्थिर तरीकों के माध्यम से सुलभ बना दिया हो जाएगा, संभव नहीं है। जैसे

object Foo { 
    def bar = 2 
} 

हो जाएगा कुछ की तरह:

public final class Foo { 
    public static int bar() { 
    return Foo..MODULE$.bar(); 
    } 
} 

public final class Foo$ 
    implements ScalaObject 
{ 
    public static final MODULE$; 

    static 
    { 
    new(); 
    } 

    public int bar() 
    { 
    return 2; 
    } 

    private Foo$() 
    { 
    MODULE$ = this; 
    } 
} 

क्या निहित रूपांतरण विधि में पारित हो जाता है इस मामले Foo..MODULE $ किस प्रकार फू $ का एक उदाहरण है में है। जावा स्टेटिक्स में अंतर्निहित सिंगलटन उदाहरण नहीं है और इसलिए किसी अन्य प्रकार में परिवर्तित होने के लिए किसी फ़ंक्शन में पारित नहीं किया जा सकता है।

उम्मीद है कि यह समझने में थोड़ा सा मदद करता है कि यह क्यों संभव नहीं है ;-)।

1

हालांकि आप इस तरह के सिंगलटन ऑब्जेक्ट्स में निहित रूपांतरण द्वारा कोई विधि नहीं जोड़ सकते हैं, आप वास्तविक निर्माण करने के लिए एक अंतर्निहित पैरामीटर का उपयोग कर सकते हैं। उदाहरण के लिए:

trait Factory1[-A,+B] { 
    def buildFrom(a: A): B 
} 

trait Factory2[-A1,-A2,+B] { 
    def buildFrom(a1: A1, a2: A2): B 
} 

object Factories { 
    implicit object GeoPointFromLocation extends Factory1[Location,GeoPoint] { 
    def buildFrom(location: Location): GeoPoint = //actual code 
    } 
    implicit object GeoPointFromXY extends Factory2[Double,Double,GeoPoint] { 
    def buildFrom(x: Double, y: Double): GeoPoint = //actual code 
    } 
} 

object GeoPoint { 
    def from[A](a: A)(implicit fac: Factory1[A,GeoPoint]) = fac.buildFrom(a) 
    def from[A,B](a: A, b: B)(implicit fac: Factory2[A,B,GeoPoint]) = fac.buildFrom(a,b) 
} 

import Factories._ 
val loc = new Location(...) 
val gp1 = GeoPoint.from(loc) 
val gp2 = GeoPoint.from(101.0, -12.6) 

तो कारखानों के रूप में आप उन्हें उम्मीद करने लगते हैं अभी भी "स्थिर" है, लेकिन आप को बेहतर बनाने के या GeoPoint वस्तु को बदलने के लिए बिना व्यवहार बदल सकते हैं। उदाहरण के लिए आप परीक्षण करते समय विशेष कारखानों का आयात कर सकते हैं।

इस दृष्टिकोण का उपयोग स्कैला लाइब्रेरी में किया जाता है, उदाहरण के लिए जेनेरिक Traversable विधियों जैसे map लागू करने पर सही संग्रह प्रकार बनाने के लिए।

+0

... जो 'आयातित भू-पॉइंट की ओर जाता है, पैकेज में ऑब्जेक्ट जियोपॉइंट की परिभाषा द्वारा स्थायी रूप से छिपा हुआ है ...' तो मुझे लगता है कि यह वास्तव में अभ्यास में काम नहीं करता है :-( – Leo

0

यह संभव नहीं है, लेकिन आप एक पैकेज वस्तु में एक ही वर्ग के नाम के साथ एक साथी वस्तु है और इसका इस्तेमाल के रूप में आप चाहते थे कर सकते हैं,

import com.google.android.maps.GeoPoint 

package object com.xyz.mappy.maps { 
    object GeoPoint {   
    def from(....): GeoPoint = new GeoPoint(...) 
    } 
} 


................................. 

package com.xyz.mappy.maps 

import com.google.android.maps.GeoPoint 

class MapRenderer { 

    val geopoint = GeoPoint.from(...) 

}