क्या ऐसी परिस्थितियाँ हैं जहाँ आपको गैर-मामले वर्ग को प्राथमिकता देनी चाहिए?
मार्टिन ओडस्की हमें अपने कोर्स फंकल (लेक्चर 4.6 - पैटर्न मिलान) में कार्यात्मक प्रोग्रामिंग सिद्धांतों का एक अच्छा प्रारंभिक बिंदु देता है जिसका उपयोग हम तब कर सकते हैं जब हमें क्लास और केस क्लास के बीच चयन करना होगा। स्केल बाय उदाहरण के अध्याय 7 में एक ही उदाहरण है।
कहते हैं, हम अंकगणितीय अभिव्यक्तियों के लिए एक दुभाषिया लिखना चाहते हैं। शुरू में चीजों को सरल रखने के लिए, हम अपने आप को सिर्फ संख्याओं और परिचालनों तक सीमित रखते हैं। ऐसे एक्सरे- sions को एक वर्ग पदानुक्रम के रूप में दर्शाया जा सकता है, एक मूल आधार वर्ग के रूप में मूल के रूप में Expr, और दो उपवर्ग संख्या और Sum। फिर, एक अभिव्यक्ति 1 + (3 + 7) के रूप में प्रतिनिधित्व किया जाएगा
नया योग (नया नंबर (1), नया योग (नया नंबर (3), नया नंबर) (7))
abstract class Expr {
def eval: Int
}
class Number(n: Int) extends Expr {
def eval: Int = n
}
class Sum(e1: Expr, e2: Expr) extends Expr {
def eval: Int = e1.eval + e2.eval
}
इसके अलावा, एक नया उत्पाद वर्ग जोड़ने से मौजूदा कोड में कोई परिवर्तन नहीं होता है:
class Prod(e1: Expr, e2: Expr) extends Expr {
def eval: Int = e1.eval * e2.eval
}
इसके विपरीत, एक नई विधि जोड़ने के लिए सभी मौजूदा वर्गों के संशोधन की आवश्यकता होती है।
abstract class Expr {
def eval: Int
def print
}
class Number(n: Int) extends Expr {
def eval: Int = n
def print { Console.print(n) }
}
class Sum(e1: Expr, e2: Expr) extends Expr {
def eval: Int = e1.eval + e2.eval
def print {
Console.print("(")
print(e1)
Console.print("+")
print(e2)
Console.print(")")
}
}
केस कक्षाओं के साथ एक ही समस्या हल हुई।
abstract class Expr {
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
}
}
case class Number(n: Int) extends Expr
case class Sum(e1: Expr, e2: Expr) extends Expr
एक नई विधि जोड़ना एक स्थानीय परिवर्तन है।
abstract class Expr {
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
}
def print = this match {
case Number(n) => Console.print(n)
case Sum(e1,e2) => {
Console.print("(")
print(e1)
Console.print("+")
print(e2)
Console.print(")")
}
}
}
एक नए उत्पाद वर्ग को जोड़ने के लिए सभी पैटर्न के मिलान में संभावित बदलाव की आवश्यकता होती है।
abstract class Expr {
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
case Prod(e1,e2) => e1.eval * e2.eval
}
def print = this match {
case Number(n) => Console.print(n)
case Sum(e1,e2) => {
Console.print("(")
print(e1)
Console.print("+")
print(e2)
Console.print(")")
}
case Prod(e1,e2) => ...
}
}
Videolecture से प्रतिलेख 4.6 पैटर्न मिलान
ये दोनों डिज़ाइन पूरी तरह से ठीक हैं और उनके बीच चयन करना कभी-कभी शैली का विषय होता है, लेकिन फिर भी कुछ मापदंड हैं जो महत्वपूर्ण हैं।
एक मानदंड हो सकता है, क्या आप अधिक बार अभिव्यक्ति के नए उप-वर्ग बना रहे हैं या आप अधिक बार नए तरीके बना रहे हैं? तो यह एक ऐसी कसौटी है जो भविष्य की व्यापकता और आपके सिस्टम के संभावित विस्तार पास को देखता है।
यदि आप जो करते हैं वह ज्यादातर नए उपवर्गों का निर्माण करता है, तो वास्तव में वस्तु उन्मुख अपघटन समाधान का ऊपरी हाथ होता है। कारण यह है कि यह बहुत आसान है और एक बहुत ही स्थानीय परिवर्तन सिर्फ एक नया तरीका बनाने के लिए एक eval पद्धति के साथ , जिसमें , जिसमें , जहां कार्यात्मक समाधान के रूप में, आपको वापस जाना होगा और कोड को eval विधि के अंदर बदलना होगा और एक नया केस जोड़ना होगा। यह करने के लिए।
दूसरी ओर, यदि आप क्या करते हैं , तो बहुत सारे नए तरीके बनाए जाएंगे, लेकिन वर्ग पदानुक्रम को अपेक्षाकृत स्थिर रखा जाएगा, फिर पैटर्न मिलान वास्तव में लाभप्रद है। क्योंकि, फिर से, पैटर्न मिलान समाधान में प्रत्येक नई विधि सिर्फ एक स्थानीय परिवर्तन है , चाहे आप इसे आधार वर्ग में रखें, या शायद वर्ग पदानुक्रम के बाहर भी। जबकि एक नई विधि जैसे ऑब्जेक्ट ओरिएंटेड अपघटन में शो को एक नई वृद्धि की आवश्यकता होगी प्रत्येक उप वर्ग है। तो और भी हिस्से होंगे, जिन्हें आपको छूना है।
तो इस विलुप्त होने की समस्या दो आयामों में है, जहाँ आप नई कक्षाओं को पदानुक्रम में जोड़ना चाह सकते हैं, या आप नए तरीकों को जोड़ना चाह सकते हैं, या शायद दोनों को, अभिव्यक्ति समस्या का नाम दिया गया है ।
याद रखें: हमें इसका इस्तेमाल एक शुरुआती बिंदु की तरह करना चाहिए, न कि एकमात्र मापदंड की तरह।