DesignPatterns, दुभाषिया टेम्पलेट

भाषा के संकलक और व्याख्याकार, एक नियम के रूप में, अन्य भाषाओं में लिखे गए हैं (कम से कम यह पहले था)। उदाहरण के लिए, PhP को C. में लिखा गया था। जैसा कि आपने PhP में अनुमान लगाया था, आप अपनी भाषा के लिए अपने स्वयं के संकलक को परिभाषित, डिजाइन और लिख सकते हैं। बेशक, हम जो भाषा बनाते हैं, वह धीरे-धीरे काम करेगी और सीमित होगी, हालांकि, यह बहुत उपयोगी हो सकती है।

और इसलिए एक समस्या पैदा करें जिसे हल करने की आवश्यकता है

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

$input = $_REQUEST['input']; // «print file_get_contents('/etc/passwd'); eval($input); 


जाहिर है, इस विधि को सामान्य नहीं कहा जा सकता है। लेकिन अगर यह आपके लिए स्पष्ट नहीं है, तो इसके दो कारण हैं: सुरक्षा और जटिलता।

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

उदाहरण प्रश्न:
हमारे सौर मंडल में कितने ग्रह हैं?
हम उत्तर "आठ", "8" को सही उत्तरों के रूप में स्वीकार कर सकते हैं। बेशक, यह आपके सभी पसंदीदा नियमित अभिव्यक्तियों की मदद से हल किया जा सकता है, ^ 8 | आठ $।
लेकिन दुर्भाग्य से, सभी डेवलपर्स उन्हें नहीं जानते हैं। इसलिए, आइए अधिक अनुकूल इंटरफ़ेस लागू करें:

$input equals «8» or $input equals «»

आपको एक ऐसी भाषा बनाने की ज़रूरत है जो चर, समान ऑपरेटर और बूलियन तर्क (या, और) का समर्थन करती है। चूँकि हम सभी को सब कुछ कॉल करने का शौक है, आइए अपनी भाषा में कहें, गो लाइजिक
हमारी भाषा को स्पष्ट रूप से विस्तारित किया जाना चाहिए, क्योंकि हम अधिक जटिल कार्यों के लिए कई अनुरोधों की आशा करते हैं। हम इनपुट डेटा के विश्लेषण के सवाल को छोड़ देंगे और प्रतिक्रिया उत्पन्न करने के लिए इन तत्वों को जोड़ने के लिए तंत्र की वास्तुकला पर आगे बढ़ेंगे।

कार्यान्वयन

यहां तक ​​कि हमारी छोटी भाषा में, बहुत सारे तत्वों को ट्रैक करना आवश्यक है: चर, स्ट्रिंग शाब्दिक, बूलियन और बूलियन या, और समानता की जाँच।
हम उन्हें कक्षाओं में विभाजित करते हैं:
छवि

चलो एक छोटा चित्र बनाते हैं:
छवि

कोड का एक बिट:
 abstract class Expression { private static $keycount = 0; private $key; abstract function interpret(InterpreterContext $context); function getKey() { if (!isset($this->key)) { self::$keycount++; $this->key = self::$keycount; } return $this->key; } } class LitralExpr extends Expression { private $value; function __construct($value) { $this->value = $value; } public function interpret(InterpreterContext $context) { $context->replace($this, $this->value); } } class InterpreterContext { private $exprstore = array(); function replace(Expression $exp, $value) { $this->exprstore[$exp->getKey()] = $value; } function lookup(Expression $exp) { return $this->exprstore[$exp->getKey()]; } } 


InterpreterContext केवल सहयोगी सरणी $ exprstore के लिए एक इंटरफ़ेस प्रदान करता है जिसका उपयोग हम डेटा स्टोर करने के लिए करते हैं। हम कुंजी और मूल्य को प्रतिस्थापित करने के लिए पास करते हैं () विधि, डेटा को पुनः प्राप्त करने के लिए लुकअप () विधि भी लागू की जाती है।
अभिव्यक्ति वर्ग एक सार व्याख्या () विधि और एक विशिष्ट getKey () विधि को परिभाषित करता है; एक स्थिर काउंटर मान के साथ काम करते हुए, इसे एक एक्सप्रेशन डिस्क्रिप्टर के रूप में दिया जाता है;
लिटरल एक्सप्रैस वर्ग एक निर्माण को परिभाषित करता है जिसके लिए एक मूल्य तर्क पारित किया जाता है। इंटरप्ट () विधि को इंटरप्रेटर कॉन्टेक्स के एक प्रकार से पास करने की आवश्यकता है, हम बस रिप्लेसमेंट () विधि को कॉल करते हैं
अब शेष VariableExpr वर्ग को परिभाषित करें।
 class VariableExpr extends Expression { private $name; private $val; public function __construct($name, $val = null) { $this->name = $name; $this->val = $val; } public function interpret(InterpreterContext $context) { if (!is_null($this->val)) { $context->replace($this, $this->val); $this->val = null; } } function setValue($val) { $this->val = $val; } function getKey() { return $this->name; } } 


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

 abstract class OperatorExpr extends Expression { protected $l_op; protected $r_op; function __construct(Expression $l_op, Expression $r_op) { $this->l_op = $l_op; $this->r_op = $r_op; } function interpret(InterpreterContext $context) { $this->l_op->interpret($context); $this->r_op->interpret($context); $result_l = $context->lookup($this->l_op); $result_r = $context->lookup($this->r_op); $this->doInterpret($context, $result_l, $result_r); } protected abstract function doInterpret(InterpreterContext $context, $result_l, $result_r); } 


DoInpretpret () विधि टेम्पलेट विधि का एक उदाहरण है। इस टेम्पलेट में, सार पद्धति को परिभाषित किया गया है और मूल वर्ग में कहा जाता है, जिसके कार्यान्वयन को बाल कक्षाओं में छोड़ दिया जाता है। यह विशिष्ट कक्षाओं के विकास को सरल बना सकता है, क्योंकि सुपर क्लास साझा कार्यों का प्रबंधन करता है, जिससे बच्चे को स्पष्ट और समझने योग्य लक्ष्यों पर ध्यान केंद्रित करना पड़ता है।

 class EqualsExpr extends OperatorExpr { protected function doInterpret(InterpreterContext $context, $result_l, $result_r) { $context->replace($this, $result_l == $result_r); } } class BoolOrExpr extends OperatorExpr { protected function doInterpret(InterpreterContext $context, $result_l, $result_r) { $context->replace($this, $result_l || $result_r); } } class BoolAndExpr extends OperatorExpr { protected function doInterpret(InterpreterContext $context, $result_l, $result_r) { $context->replace($this, $result_l && $result_r); } } 


अब जब हमने कक्षाएं और एक छोटी प्रणाली तैयार की है, तो हम थोड़ा कोड निष्पादित करने के लिए तैयार हैं। क्या आप अब भी उसे याद करते हैं?
$input equals «8» or $input equals «»

 $context = new InterpreterContext(); $input = new VariableExpr('input'); $stats = new BoolOrExpr(new EqualsExpr($input, new LitralExpr('')), new EqualsExpr($input, new LitralExpr('8'))); foreach (array("", "8", "666") as $val) { $input->setValue($val); print "$val:\n"; $stats->interpret($context); if($context->lookup($stats)) { print '\n\n'; } else { print " \n\n"; } } 


हमारे सिस्टम में अभी भी एक पार्सर की कमी है, आप अपना खुद का लिख ​​सकते हैं या एक मौजूदा ले सकते हैं। जटिल प्रणालियों के लिए, मौजूदा इंजन को लेना बेहतर है।

छवि
दुभाषिया पैटर्न के मुद्दे

एक बार जब आप इंटरप्रेटर टेम्पलेट को लागू करने के लिए मुख्य कक्षाएं तैयार कर लेते हैं, तो इसका विस्तार करना आसान होगा। इसके लिए आपको जो कीमत चुकानी होगी, वह केवल उन वर्गों की संख्या है, जिन्हें आपको बनाने की आवश्यकता है। इसलिए, यह पैटर्न अपेक्षाकृत छोटी भाषाओं के लिए अधिक लागू है। और यदि आपको एक पूर्ण प्रोग्रामिंग भाषा की आवश्यकता है, तो इसके लिए तीसरे पक्ष की कंपनियों के टूल की तलाश करना बेहतर है।

चूंकि दुभाषिया वर्ग अक्सर बहुत समान कार्य करते हैं, इसलिए नकल से बचने के लिए बनाई जा रही कक्षाओं का ध्यान रखना सार्थक है

सूत्रों का कहना है:
गैंग ऑफ़ फोर टेम्प्लेट

Source: https://habr.com/ru/post/In136371/


All Articles