2012-04-24 33 views
5

मेरे पास दो केस क्लास हैं जो एक सार आधार वर्ग से प्राप्त होते हैं। मैं अमूर्त बेस क्लास पर कुछ विधियों को परिभाषित करना चाहता हूं जो विरासत केस कक्षाओं पर कॉपी विधियों का उपयोग करते हैं (और इसलिए बाल वर्ग का एक उदाहरण लौटाते हैं।) क्या स्वयं प्रकारों का उपयोग करके ऐसा करने का कोई तरीका है?स्कैला: क्या माता-पिता वर्ग के लिए केवल बच्चों द्वारा परिभाषित विधियों तक पहुंचने का कोई तरीका है?

उदाहरण कोड:

abstract class BaseClass(a: String, b: Int) { 
    this: case class => //not legal, but I'm looking for something similar 

    def doubleB(newB: Int) = this.copy(b = b * 2) //doesn't work because BaseClass has no copy 
} 

case class HasC(a: String, b: Int, c: Boolean) extends BaseClass(a, b) { 
    def doesStuffWithC(newC: Boolean) = { 
    ... 
    } 
} 

case class HasD(a: String, b: Int, D: Double) extends BaseClass(a, b) { 
    def doesStuffWithD(newD: Double) = { 
    ... 
    } 
} 

मैं समझ गए होंगे कि कैसे परिणाम मैं इस सवाल के लिए धन्यवाद चाहते हैं: How to use Scala's this typing, abstract types, etc. to implement a Self type? लेकिन यह BaseClass करने के लिए एक makeCopy विधि जोड़ने और के लिए एक कॉल के साथ यह अधिभावी शामिल प्रत्येक बच्चे के मामले वर्गों में प्रतिलिपि बनाएँ, और वाक्यविन्यास (विशेष रूप से स्वयं के प्रकार के लिए) काफी उलझन में है। स्केल के स्वयं टाइपिंग में निर्मित के साथ ऐसा करने का कोई तरीका है?

+2

किसी ने जवाब दिया कि केस वर्ग सभी 'उत्पाद' का विस्तार करते हैं, जो सत्य है, लेकिन इसे हटा दिया गया था, संभवतः क्योंकि 'प्रति'' उत्पाद 'पर परिभाषित नहीं किया गया है, इसलिए यह स्वयं प्रकार के लिए इसका उपयोग करने के लिए काम नहीं करता है। 'उत्पाद' के लिए दस्तावेज़ कहता है "सभी केस वर्ग सिंथेटिक रूप से जेनरेट किए गए तरीकों के साथ उत्पाद को लागू करते हैं" - क्या इसका मतलब है कि मैं भाग्य से बाहर हूं? –

उत्तर

5

आप जो भी चाहते हैं वह नहीं कर सकते क्योंकि copyसभी संभावित पैरामीटर के बारे में जानना आवश्यक है। इसलिए यदि Copyable से केस क्लास विरासत में मिला है, तो यह आवश्यक नहीं होगा copy। इसके अलावा, यदि आप सीधे प्रकारों को रखने जा रहे हैं, तो आप स्कैला की "MyType" की कमी से विफल हो जाएंगे। तो आप नहीं कर सकते हैं आधार श्रेणी का विस्तार करें। हालांकि, अगर आप एक सार विधि और प्रकार एनोटेशन जोड़ सकते हैं:

abstract class BaseClass[C <: BaseClass[_]](a: String, b: Int) { 
    def setB(b0: Int): C 
    def doubleB(b0: Int) = setB(b0*2) 
} 
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass[HasC](a,b) { 
    def setB(b0: Int) = this.copy(b = b0) 
    def doesStuffWithC(c0: Boolean) = doubleB(if (c0) b else -b).copy(c = c0) 
} 

और फिर आप कर सकते हैं:

scala> HasC("fish",1,false).doesStuffWithC(true) 
res47: HasC = HasC(fish,2,true) 

इस अतिरिक्त काम करता है, तो आप साझा कार्यक्षमता का एक बहुत पर निर्भर करता है कि है इसके लायक हो जाएगा b (या तो कई विधियों, या जटिल तरीकों की एक छोटी संख्या) की प्रतिलिपि बनाने की क्षमता - यानी, यह DRY समस्या हल करती है। आप HasC और अन्य व्युत्पन्न वर्ग से अधिक सार चाहते हैं बजाय, आप BaseClass[_] उपयोग कर सकते हैं या अभी तक एक स्तर है कि setB(b0: Int): BaseBase को परिभाषित करता है जोड़ सकते हैं या बस प्रकार parameterization भूल जाते हैं और वापसी प्रकार के रूप में BaseClass उपयोग करें (लेकिन मानते हैं कि HasCBaseClass विधियों का उपयोग नहीं कर सकते हैं और अभी भी अपनी प्रकार की पहचान बनाए रखें)।

+0

यह जो मैंने कार्यान्वित किया है उसके करीब है। बेस क्लास पर टाइप पैरामीटर के रूप में बाल वर्ग की परिभाषा को लागू करना उपरोक्त "स्वयं प्रकार" प्रश्न में सुझाए गए वाक्यविन्यास की तुलना में क्लीनर है, इसलिए मैंने इसे शामिल किया है - धन्यवाद! –

1

मुझे लगता है कि आप भाग्य से बाहर हैं। HasC और HasD पर विधियों के अलग-अलग हस्ताक्षर हैं। यह डिफ़ॉल्ट तर्कों के कारण थोड़ा छिपा हुआ है, लेकिन मूल रूप से BaseClass में परिभाषा को पता नहीं चलेगा कि कौन से copy कॉल करने की विधि है।

1

आप अमूर्त वर्ग में मेकॉपी परिभाषित कर सकते हैं जो एक कॉपियर फ़ंक्शन लेता है जो यूनिट लेता है और बेसक्लास लौटाता है, फिर, इसका उपयोग करने वाले तरीकों में (जैसे डबलबी) उन्हें केस क्लास निकायों में ओवरराइड करता है और मेकॉपी का उपयोग करता है

package delegatedcopy 

abstract class BaseClass(a: String, b:Int){ 
    def aField = a 
    def bField = b 
    def doubleB:BaseClass 
    def makeCopy(copier:() => BaseClass):BaseClass = copier() 
} 

case class HasC(override val aField: String, override val bField: Int, cField: Boolean) extends BaseClass(aField, bField){ 
    override def doubleB:BaseClass = makeCopy(()=> HasC(aField, bField * 2, cField)) 
} 

case class HasD(override val aField: String, override val bField: Int, dField:Double) extends BaseClass(aField, bField){ 
    override def doubleB:BaseClass = makeCopy(()=> HasD(aField, bField * 2, dField)) 
} 

एक परीक्षण एप्लिकेशन है कि यह दर्शाता है: यह एक गुमनाम समारोह है कि रंगमंच की सामग्री के साथ एक नई प्रतिलिपि बनाने का काम, बदला तो तरह है पारित करके

import delegatedcopy._ 

object TestApp extends Application{ 
    val hasC = HasC("A C object", 5, true) 
    val hasD = HasD("A D object", 2, 3.55) 
    val hasCDoubleB = hasC.doubleB 
    val hasDDoubleB = hasD.doubleB 

    println(hasC) // prints HasC(A C object,5,true) 
    println(hasCDoubleB) //prints HasC(A C object,10,true) 

    println(hasD) // prints HasD(A D object,2,3.55) 
    println(hasDDoubleB) // prints HasD(A D object,4,3.55) 
} 

इस तरह, आप कर रहे हैं मेकॉपी विधि को सभी बच्चों के लिए समान रखने में सक्षम है कक्षाओं के रूप में कक्षाएं, और संभवतः आधार और केस कक्षाओं में काफी कार्यक्षमता में कार्यान्वित या मिश्रण कर सकती हैं जबकि एक सुरक्षित स्थान पर सामान्य कोड रखते हुए और विशिष्ट केस कक्षाओं पर ग्राहकों को बेस क्लास और पैटर्न मिलान पास करने में सक्षम होते हैं।