2011-01-23 4 views
5

मैं एक सामान्य वेक्टर सार वर्ग/विशेषता है कि कुछ तरीकों को निर्दिष्ट करता है, उदाहरण के लिए करना चाहते हैं:उचित वर्ग पदानुक्रम वैक्टर

trait Vec 
{ 
    def +(v:Vec):Vec 
    def *(d:Double):Vec 

    def dot(v:Vec):Double 
    def norm:Double 
} 

मैं Vec2D और Vec3D का विस्तार करना चाहते हैं Vec:

class Vec2D extends Vec { /* implementation */ } 
class Vec3D extends Vec { /* implementation */ } 

लेकिन उदाहरण के लिए, मैं इसे कैसे बना सकता हूं ताकि Vec2D को केवल Vec2D में जोड़ा जा सके और Vec3D पर नहीं जोड़ा जा सके?

अभी मैं सिर्फ एक आम Vec पूर्वज के बिना Vec2D और Vec3D को लागू कर रहा हूँ, लेकिन यह डुप्लिकेट कोड के साथ कठिन हो रही है। मैं अपने सभी ज्यामिति वर्गों है कि इन कक्षाओं पर निर्भर करते हैं लागू करने के लिए (जैसे कि Triangle, Polygon, Mesh, ...) दो बार, Vec2D के लिए एक बार और फिर Vec3D के लिए।

मुझे जावा कार्यान्वयन दिखाई देता है: javax.vecmath.Vector2d और javax.vecmath.Vector3d कोई आम पूर्वज नहीं है। इसके लिए क्या कारण है? क्या स्कैला में इसे दूर करने का कोई तरीका है?

उत्तर

5

requested के रूप में, आधार विशेषता को डिजाइन करने का सबसे उपयोगी तरीका शामिल है दोनों CRTPऔरself-type annotation विचार करना चाहिए।

trait Vec[T <: Vec[T]] { this: T => 
    def -(v: T): T 
    def *(d: Double): T 

    def dot(v: T): Double 
    def norm: Double = math.sqrt(this dot this) 
    def dist(v: T) = (this - v).norm 
} 

आत्म प्रकार के बिना, यह कॉल करने के लिए this.dot(this)dot के रूप में एक T उम्मीद संभव नहीं है; इसलिए हमें इसे एनोटेशन के साथ लागू करने की आवश्यकता है।

दूसरी ओर, CRTP के बिना, हम (this - v)- के रूप में रिटर्न एक T और इस प्रकार हम सुनिश्चित करें कि हमारे प्रकार T इस विधि, उदा है बनाने की जरूरत है पर norm कॉल करने के लिए असफल हो जाएगा घोषणा करें कि TएकVec[T] है।

4

मुझे उचित स्कैला वाक्यविन्यास के बारे में निश्चित नहीं है, लेकिन आप CRTP को कार्यान्वित कर सकते हैं, यानी वास्तविक प्रकार को सामान्य पैरामीटर के माध्यम से परिभाषित कर सकते हैं।

trait Vec[V <: Vec[V]] { 
    def +(v:V):V 
    ... 
} 

class Vec2D extends Vec[Vec2D] { } 
class Vec3D extends Vec[Vec3D] { } 

class Polygon[V <: Vec[V]] { 
    ... 
} 
+0

स्पॉट पर। सिंटेक्स सही है और सबकुछ! मुझे लगता है कि जावा इसका समर्थन नहीं करता है (अन्यथा 'javax.vecmath' के साथ सौदा क्या है)? – dsg

+0

दरअसल, मुझे लगता है कि जावा इसका समर्थन करता है: http://stackoverflow.com/questions/2382915/what-does-this-java-generics-paradigm-do-and-what-is-it-called – dsg

7

आप स्वयं प्रकार का उपयोग कर सकते हैं:

trait Vec[T] { self:T => 
    def +(v:T):T 
    def *(d:Double):T 

    def dot(v:T):Double 
    def norm:Double 
} 

class Vec2D extends Vec[Vec2D] { /* implementation */ } 
class Vec3D extends Vec[Vec3D] { /* implementation */ } 

लेकिन अगर दोनों कार्यान्वयन बहुत समान हैं, आप भी आयाम से अधिक सार की कोशिश कर सकते।

sealed trait Dimension 
case object Dim2D extends Dimension 
case object Dim3D extends Dimension 

sealed abstract class Vec[D <: Dimension](val data: Array[Double]) { 

    def +(v:Vec[D]):Vec[D] = ... 
    def *(d:Double):Vec[D] = ... 

    def dot(v:Vec[D]):Double = ... 
    def norm:Double = math.sqrt(data.map(x => x*x).sum) 
} 

class Vec2D(x:Double, y:Double) extends Vec[Dim2D.type](Array(x,y)) 
class Vec3D(x:Double, y:Double, z:Double) extends Vec[Dim3D.type](Array(x,y,z)) 

बेशक यह कैसे आप डेटा का प्रतिनिधित्व करना चाहते हैं पर निर्भर करता है, और यदि आप अस्थायी या अपरिवर्तनीय उदाहरण सामने आना चाहते हैं। और "वास्तविक दुनिया" अनुप्रयोगों के लिए आप http://code.google.com/p/simplex3d/

+0

स्वयं प्रकार आपको अनुमति देते हैं 'इस' को संदर्भित करने के लिए, जबकि डारियो के उत्तर में सीआरटीपी पैटर्न नहीं है। – dsg

+0

@dsg: क्या मतलब है कि आप 'इस' को सीआरटीपी के साथ संदर्भित नहीं कर सकते? – Debilski

+1

ठीक है, आप नहीं कर सकते। – Debilski

2

जेवीएम पर सीआरटीपी पैटर्न के साथ एक आम पूर्वजों के साथ एक बड़ी समस्या है। जब आप अलग-अलग कार्यान्वयन के साथ एक ही सार कोड निष्पादित करते हैं, तो JVM कोड को डी-ऑप्टिमाइज़ करेगा (कोई इनलाइनिंग + आभासी कॉल नहीं)। यदि आप केवल Vec3D के साथ परीक्षण करते हैं, तो आप इसे नोटिस नहीं करेंगे, लेकिन यदि आप Vec2D और Vec3D दोनों के साथ परीक्षण करते हैं तो आपको प्रदर्शन में एक बड़ी गिरावट दिखाई देगी। इसके अलावा, एस्केप विश्लेषण डी-ऑप्टिमाइज़ कोड पर लागू नहीं किया जा सकता है (कोई स्केलर प्रतिस्थापन नहीं, नए उदाहरणों का कोई उन्मूलन नहीं)। इन अनुकूलन की कमी आपके प्रोग्राम को 3 के कारक से धीमा कर देगी (बहुत गोल अनुमान जो आपके कोड पर निर्भर करता है)।

कुछ बेंचमार्क आज़माएं जो लगभग 10 सेकंड तक चलते हैं। Vec2D के साथ एक ही रन परीक्षण में, फिर Vec3D, फिर Vec2D, फिर Vec3D फिर से। आप इस पैटर्न देखेंगे:

  • Vec2D ~ 10 सेकंड
  • Vec3D ~ 30 सेकंड
  • Vec2D ~ 30 सेकंड
  • Vec3D ~ 30 सेकंड

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

  • कोई संबंधित समस्या नहीं^_^