अद्यतन २०१६/०२/२५:
जबकि मैंने जो उत्तर नीचे लिखा था, वह पर्याप्त है, यह मामला वर्ग के साथी वस्तु के संबंध में एक और संबंधित उत्तर का उल्लेख करने योग्य है। अर्थात्, कंपाइलर उत्पन्न निहित साथी वस्तु को वास्तव में कैसे पुन: उत्पन्न करता है जो तब होता है जब कोई केवल केस क्लास को ही परिभाषित करता है। मेरे लिए, यह जवाबी सहजता से निकला।
सारांश:
आप केस क्लास के पैरामीटर के मान को केस क्लास में संग्रहीत करने से पहले बहुत आसानी से बदल सकते हैं, जबकि यह अभी भी एक मान्य (एटेड) एडीटी (सार डेटा प्रकार) शेष है। जबकि समाधान अपेक्षाकृत सरल था, विवरणों की खोज करना थोड़ा अधिक चुनौतीपूर्ण था।
विवरण:
यदि आप यह सुनिश्चित करना चाहते हैं कि आपके केस क्लास के केवल मान्य इंस्टेंट को कभी भी तत्काल किया जा सकता है जो कि ADT (अमूर्त डेटा टाइप) के पीछे एक आवश्यक धारणा है, तो आपको बहुत सी चीजें करनी चाहिए।
उदाहरण के लिए, कंपाइलर जेनरेट की गई copy
विधि किसी केस क्लास पर डिफ़ॉल्ट रूप से प्रदान की जाती है। इसलिए, भले ही आप यह सुनिश्चित करने के लिए बहुत सतर्क थे कि केवल स्पष्ट साथी ऑब्जेक्ट apply
विधि के माध्यम से बनाया गया था, जो गारंटी देता था कि वे केवल ऊपरी मामले मानों को शामिल कर सकते हैं, निम्न कोड निम्न केस वैल्यू के साथ केस क्लास इंस्टेंस उत्पन्न करेगा:
val a1 = A("Hi There")
val a2 = a1.copy(s = "gotcha")
इसके अतिरिक्त, केस कक्षाएं लागू होती हैं java.io.Serializable
। इसका मतलब यह है कि केवल ऊपरी मामले में आपके सावधान रणनीति को सरल पाठ संपादक और डीरियलाइज़ेशन के साथ बदल दिया जा सकता है।
इसलिए, सभी विभिन्न तरीकों के लिए आपके केस क्लास का उपयोग किया जा सकता है (परोपकारी और / या पुरुष रूप से), यहां वे क्रियाएं हैं जिन्हें आपको लेना चाहिए:
- अपने स्पष्ट साथी वस्तु के लिए:
- अपने केस क्लास के समान नाम का उपयोग करके इसे बनाएं
- इससे केस क्लास के प्राइवेट पार्ट्स तक पहुंच है
apply
अपने केस क्लास के लिए प्राथमिक कंस्ट्रक्टर के समान हस्ताक्षर के साथ एक विधि
बनाएं
- एक बार 2.1 चरण पूरा होने पर यह सफलतापूर्वक संकलन करेगा
new
ऑपरेटर का उपयोग करके केस क्लास का एक उदाहरण प्राप्त करने वाला एक कार्यान्वयन प्रदान करें और एक खाली कार्यान्वयन प्रदान करें{}
- यह अब आपकी शर्तों पर केस क्लास को सख्ती से लागू करेगा
- खाली कार्यान्वयन
{}
प्रदान किया जाना चाहिए क्योंकि मामला वर्ग घोषित किया गया है abstract
(चरण 2.1 देखें)
- आपके केस क्लास के लिए:
- इसकी घोषणा करें
abstract
- स्केल कंपाइलर
apply
को साथी ऑब्जेक्ट में एक विधि उत्पन्न करने से रोकता है जो कि "विधि को दो बार परिभाषित किया गया है ..." संकलन त्रुटि (चरण 1.2 ऊपर) है
- प्राथमिक निर्माता के रूप में चिह्नित करें
private[A]
- प्राथमिक कंस्ट्रक्टर अब केवल केस क्लास और उसके साथी ऑब्जेक्ट के लिए उपलब्ध है (जिसे हमने चरण 1.1 में ऊपर परिभाषित किया है)
- एक
readResolve
विधि
बनाएँ
- लागू विधि का उपयोग करके एक कार्यान्वयन प्रदान करें (चरण 1.2 ऊपर)
- एक
copy
विधि
बनाएँ
- इसे परिभाषित करें कि केस क्लास के प्राथमिक कंस्ट्रक्टर के समान ही हस्ताक्षर हैं
- प्रत्येक पैरामीटर के लिए, एक ही पैरामीटर नाम का उपयोग करके डिफ़ॉल्ट मूल्य जोड़ने (पूर्व:
s: String = s
)
- लागू पद्धति का उपयोग करके एक कार्यान्वयन प्रदान करें (चरण 1.2 नीचे)
यहां उपरोक्त क्रियाओं के साथ आपका कोड संशोधित किया गया है:
object A {
def apply(s: String, i: Int): A =
new A(s.toUpperCase, i) {}
}
abstract case class A private[A] (s: String, i: Int) {
private def readResolve(): Object =
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
और आवश्यकता को लागू करने के बाद यहां आपका कोड है (@ollekullberg उत्तर में सुझाव दिया गया है) और किसी भी प्रकार की कैशिंग डालने के लिए आदर्श स्थान की पहचान करना:
object A {
def apply(s: String, i: Int): A = {
require(s.forall(_.isUpper), s"Bad String: $s")
new A(s, i) {}
}
}
abstract case class A private[A] (s: String, i: Int) {
private def readResolve(): Object =
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
और यह संस्करण अधिक सुरक्षित / मजबूत है यदि इस कोड का उपयोग जावा इंटरॉप के माध्यम से किया जाएगा (केस क्लास को कार्यान्वयन के रूप में छिपाता है और एक अंतिम वर्ग बनाता है जो व्युत्पत्तियों को रोकता है):
object A {
private[A] abstract case class AImpl private[A] (s: String, i: Int)
def apply(s: String, i: Int): A = {
require(s.forall(_.isUpper), s"Bad String: $s")
new A(s, i)
}
}
final class A private[A] (s: String, i: Int) extends A.AImpl(s, i) {
private def readResolve(): Object =
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
हालांकि यह सीधे आपके प्रश्न का उत्तर देता है, उदाहरण के कैशिंग से परे केस क्लासेस के आसपास इस मार्ग का विस्तार करने के और भी तरीके हैं। अपनी स्वयं की परियोजना आवश्यकताओं के लिए, मैंने एक और भी अधिक विस्तृत समाधान तैयार किया है, जिसे मैंने CodeReview (एक StackOverflow बहन साइट) पर प्रलेखित किया है । यदि आप मेरे समाधान का उपयोग करते हुए या इसका लाभ उठाते हुए इसे समाप्त करते हैं, तो कृपया मुझे प्रतिक्रिया, सुझाव या प्रश्न छोड़ने का विचार करें और इस कारण से, मैं एक दिन में जवाब देने की पूरी कोशिश करूंगा।