Go में डिज़ाइन पैटर्न: कोई "धर्म" नहीं, बल्कि एक उपकरण
\n\nजब मैंने Go में लिखना शुरू किया, तो मुझे लगता था कि ये सभी "गैंग ऑफ फोर" और उनके 23 पैटर्न Java और C++ की दुनिया से कुछ हैं। Go तो इतना सरल और संक्षिप्त है — हमें इन जटिलताओं की क्या आवश्यकता है? लेकिन जितना अधिक मैं वास्तविक प्रोजेक्ट्स (माइक्रोसर्विसेज, CLI-उपयोगिताएँ, API हैंडलर) में गहराई से उतरता गया, उतनी ही बार मैं सोचता था: "यहाँ फैक्ट्री मेथड काम आता" या "if-else के इस ढेर को स्ट्रेटेजी से बदला जा सकता है।"
\n\nGo में डिज़ाइन पैटर्न कोई हठधर्मिता नहीं है और न ही कार्यात्मक भाषा पर OOP थोपने का प्रयास है। ये सामान्य समस्याओं के सिद्ध समाधान हैं। ये कोड को परीक्षण योग्य, लचीला और सहकर्मियों के लिए समझने योग्य बनाने में मदद करते हैं। और हाँ, Go अपनी छाप छोड़ता है: क्लासिकल इनहेरिटेंस और generics (संस्करण 1.18 से पहले) की कमी के कारण, कुछ पैटर्न बदल जाते हैं, और कुछ अनावश्यक हो जाते हैं।
\n\nइस लेख में हम सभी 23 पैटर्न की सूची नहीं देंगे। इसके बजाय, हम Golang में 5 सबसे अधिक मांग वाले टेम्पलेट्स पर चर्चा करेंगे जो वास्तविक प्रोजेक्ट्स में काम आएंगे। आप देखेंगे कि उन्हें कब लागू करना चाहिए और कब उनसे दूर भागना चाहिए।
\n\nGo में Singleton पैटर्न: सिर्फ सिंगलटन नहीं, बल्कि गो-शैली का सिंगलटन
\n\nSingleton यह सुनिश्चित करता है कि एक स्ट्रक्चर का केवल एक इंस्टेंस हो। Go में इसका उपयोग अक्सर कॉन्फिग, कनेक्शन पूल या लॉगर्स के लिए किया जाता है। लेकिन एक बारीकी है: Go में स्टैटिक क्लासेस नहीं हैं, लेकिन sync.Once है — लेज़ी इनिशियलाइज़ेशन के लिए एक आदर्श उपकरण।
Singleton के बिना समस्या
\nकल्पना करें कि आपके पास एक Config स्ट्रक्चर है जो फ़ाइल से सेटिंग्स पढ़ता है। यदि प्रत्येक पैकेज अपना इंस्टेंस बनाता है, तो आप या तो फ़ाइल को 10 बार पढ़ेंगे (धीमा) या race condition का सामना करेंगे।
Singleton के साथ समाधान
\npackage config\n\nimport (\n "sync"\n "encoding/json"\n "os"\n)\n\ntype Config struct {\n Port int `json:"port"`\n Env string `json:"env"`\n}\n\nvar (\n instance *Config\n once sync.Once\n)\n\nfunc GetConfig() *Config {\n once.Do(func() {\n file, _ := os.Open("config.json")\n defer file.Close()\n instance = &Config{}\n json.NewDecoder(file).Decode(instance)\n })\n return instance\n}\n\nकब उपयोग करें: जब इंस्टेंस की गारंटीकृत एकरूपता की आवश्यकता हो (कॉन्फिग, कैश, फैक्ट्रीज़)।
\nकब न करें: हर चीज़ के लिए नहीं। सिंगलटन एक वैश्विक स्थिति है जो परीक्षण को जटिल बनाती है। यदि कंस्ट्रक्टर के माध्यम से निर्भरता पास कर सकते हैं — तो पास करें।
\n\nFactory पैटर्न: जब ऑब्जेक्ट बनाना जटिल हो जाता है
\n\nFactory Method और Abstract Factory ऑब्जेक्ट निर्माण के तर्क को एनकैप्सुलेट करने के बारे में हैं। Go में यह विशेष रूप से प्रासंगिक है, क्योंकि हमारे पास क्लासिकल अर्थों में कंस्ट्रक्टर नहीं हैं। इसके बजाय, हम New उपसर्ग वाले कंस्ट्रक्टर फ़ंक्शन का उपयोग करते हैं।
उदाहरण: सूचनाएँ बनाना
\nमान लीजिए, आपका सिस्टम Email, SMS और Push के माध्यम से सूचनाएँ भेजता है। चयन तर्क को कोड में फैलाने के बजाय, हम फैक्ट्री का उपयोग करते हैं।
\n\npackage notification\n\nimport "fmt"\n\ntype Notifier interface {\n Send(message string) error\n}\n\ntype EmailNotifier struct{}\n\nfunc (e EmailNotifier) Send(message string) error {\n fmt.Println("Sending email:", message)\n return nil\n}\n\ntype SMSNotifier struct{}\n\nfunc (s SMSNotifier) Send(message string) error {\n fmt.Println("Sending SMS:", message)\n return nil\n}\n\nfunc NewNotifier(typ string) Notifier {\n switch typ {\n case "email":\n return EmailNotifier{}\n case "sms":\n return SMSNotifier{}\n default:\n return nil\n }\n}\n\nकब उपयोग करें: जब निर्माण तर्क जटिल हो (प्रकार, संस्करण, कॉन्फिग पर निर्भर)।
\nकब न करें: यदि आपके पास केवल एक प्रकार का ऑब्जेक्ट है। बस फैक्ट्री के बिना MyStruct{} या NewMyStruct() लिखें।