2014-09-24 4 views
39

मैं इस तथ्य से परिचित हूं कि, गो में, इंटरफ़ेस डेटा की बजाय कार्यक्षमता को परिभाषित करता है। आपने इंटरफ़ेस में विधियों का एक सेट रखा है, लेकिन आप किसी भी फ़ील्ड को निर्दिष्ट करने में असमर्थ हैं जो उस इंटरफ़ेस को लागू करने वाली किसी भी चीज़ पर आवश्यक होगा।गो इंटरफ़ेस फ़ील्ड

उदाहरण के लिए:

// Interface 
type Giver interface { 
    Give() int64 
} 

// One implementation 
type FiveGiver struct {} 

func (fg *FiveGiver) Give() int64 { 
    return 5 
} 

// Another implementation 
type VarGiver struct { 
    number int64 
} 

func (vg *VarGiver) Give() int64 { 
    return vg.number 
} 

अब हम इंटरफेस और इसके कार्यान्वयन का उपयोग कर सकते हैं:

type Person interface { 
    Name string 
    Age int64 
} 

type Bob struct implements Person { // Not Go syntax! 
    ... 
} 

func PrintName(aPerson Person) { 
    fmt.Println("Person's name is: ", aPerson.Name) 
} 

func main() { 
    b := &Bob{"Bob", 23} 
    PrintName(b) 
} 
:

// A function that uses the interface 
func GetSomething(aGiver Giver) { 
    fmt.Println("The Giver gives: ", aGiver.Give()) 
} 

// Bring it all together 
func main() { 
    fg := &FiveGiver{} 
    vg := &VarGiver{3} 
    GetSomething(fg) 
    GetSomething(vg) 
} 

/* 
Resulting output: 
5 
3 
*/ 

अब, आप ऐसा नहीं सकते हैं कि क्या कुछ इस तरह है

हालांकि, इंटरफेस और एम्बेडेड के साथ खेलने के बाद structs, मैं यह करने के लिए एक रास्ता खोज की है, एक फैशन के बाद:

type PersonProvider interface { 
    GetPerson() *Person 
} 

type Person struct { 
    Name string 
    Age int64 
} 

func (p *Person) GetPerson() *Person { 
    return p 
} 

type Bob struct { 
    FavoriteNumber int64 
    Person 
} 

एम्बेडेड struct की वजह से, बॉब सब कुछ व्यक्ति है है। यह PersonProvider इंटरफ़ेस को भी लागू करता है, इसलिए हम उस इंटरफ़ेस का उपयोग करने के लिए डिज़ाइन किए गए कार्यों में बॉब को पास कर सकते हैं।

func DoBirthday(pp PersonProvider) { 
    pers := pp.GetPerson() 
    pers.Age += 1 
} 

func SayHi(pp PersonProvider) { 
    fmt.Printf("Hello, %v!\r", pp.GetPerson().Name) 
} 

func main() { 
    b := &Bob{ 
     5, 
     Person{"Bob", 23}, 
    } 
    DoBirthday(b) 
    SayHi(b) 
    fmt.Printf("You're %v years old now!", b.Age) 
} 

Here is a Go Playground जो उपरोक्त कोड प्रदर्शित करता है।

इस विधि का उपयोग करके, मैं एक इंटरफ़ेस बना सकता हूं जो व्यवहार के बजाय डेटा को परिभाषित करता है, और जिसे उस डेटा को एम्बेड करके किसी भी संरचना द्वारा कार्यान्वित किया जा सकता है। आप उन कार्यों को परिभाषित कर सकते हैं जो उस एम्बेडेड डेटा के साथ स्पष्ट रूप से बातचीत करते हैं और बाहरी संरचना की प्रकृति से अनजान हैं। और संकलन समय पर सबकुछ जांच लिया जाता है! (एक ही तरीका है कि आप गंदगी, कि मैं देख सकता हूँ, Bob में इंटरफ़ेस PersonProvider embedding, बल्कि एक ठोस Person से हो सकता है यह संकलन और रनटाइम पर विफल हो जाएगा।।)

अब, यहाँ मेरे सवाल है: यह है एक साफ चाल है, या मैं इसे अलग तरीके से कर रहा हूँ?

+1

"मैं एक इंटरफ़ेस बना सकता हूं जो व्यवहार के बजाय डेटा को परिभाषित करता है"। मैं तर्क दूंगा कि आपके पास ऐसा व्यवहार है जो डेटा देता है। – jmaloney

+0

मैं एक उत्तर लिखने वाला हूँ; मुझे लगता है कि अगर आपको इसकी ज़रूरत है और परिणामों को पता है तो यह ठीक है, लेकिन परिणाम हैं और मैं इसे हर समय नहीं करूँगा। – twotwotwo

+0

@jmaloney मुझे लगता है कि आप सही हैं, अगर आप इसे स्पष्ट रूप से देखना चाहते हैं। लेकिन समग्र रूप से, मैंने दिखाए गए विभिन्न टुकड़ों के साथ, अर्थशास्त्र बन गए "यह फ़ंक्शन किसी भी संरचना को स्वीकार करता है जिसमें इसकी रचना में ___ है"। कम से कम, यही मेरा इरादा है। –

उत्तर

21

यह निश्चित रूप से एक साफ चाल है, और जब तक आप अपने एपीआई के हिस्से के रूप में उन क्षेत्रों तक पहुंच प्रदान करते हैं, तब तक काम करते हैं। जिस विकल्प पर मैं विचार करता हूं वह एम्बेड करने योग्य संरचना/interface सेटअप रखता है, लेकिन गेटर्स और सेटर्स के संदर्भ में इंटरफ़ेस को परिभाषित करता है।

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

तो: गेटर्स/सेटर्स के साथ, आप एक संगत एपीआई बनाए रखते हुए संरचना फ़ील्ड बदल सकते हैं, और संपत्ति के चारों ओर तर्क जोड़ सकते हैं क्योंकि कोई भी आपके कोड के बिना p.Name = "bob" कर सकता है।

यह लचीलापन अधिक प्रासंगिक होता है जब आपका प्रकार कुछ और जटिल होता है। यदि आपके पास PersonCollection है, तो इसे sql.Rows, []*Person, []uint डेटाबेस आईडी या किसी भी चीज़ द्वारा आंतरिक रूप से समर्थित किया जा सकता है।सही इंटरफ़ेस का उपयोग करके, आप कॉलर्स को यह देखभाल करने से बचा सकते हैं, जिस तरह से io.Reader नेटवर्क कनेक्शन और फ़ाइलों को समान रूप से दिखता है।

एक विशिष्ट बात: interface एस में गो में असाधारण संपत्ति है जिसे आप इसे लागू करने वाले पैकेज को आयात किए बिना कार्यान्वित कर सकते हैं; जो आपको avoid cyclic imports की मदद कर सकता है। यदि आपका इंटरफ़ेस *Person देता है, तो केवल स्ट्रिंग या जो भी हो, सभी PersonProviders को पैकेज आयात करना होगा जहां Person परिभाषित किया गया है। यह ठीक या अपरिहार्य भी हो सकता है; यह जानने के लिए सिर्फ एक परिणाम है।

सभी ने कहा कि, कोई गो सम्मेलन नहीं है जिसे आपको अपना सभी डेटा छिपाना है। (यह सी ++ से एक स्वागत अंतर है।) Stdlib चीजें करता है जैसे आपको http.Server को अपनी कॉन्फ़िगरेशन के साथ प्रारंभ करने देता है और वादा करता है कि शून्य bytes.Buffer उपयोग योग्य है। इस तरह की अपनी चीजें करना ठीक है, और, वास्तव में, मुझे नहीं लगता कि आपको अधिक ठोस, डेटा-एक्सपोज़िंग संस्करण काम करता है, तो आपको समयपूर्व अमूर्तता करना है। यह सिर्फ ट्रेडऑफ से अवगत होने के बारे में है।

+0

अच्छी तरह से कहा, धन्यवाद। –

+0

पढ़ना, मेरा जवाब वास्तव में अनुवांशिक लग रहा था क्योंकि मैं लगभग डाउनसाइड्स दे रहा था। सी ++ के विपरीत, यदि आपके लिए यह काम करता है तो डेटा को उजागर करने के लिए गो के पास कोई मतभेद नहीं है; उस पर जोर देने के लिए संपादित करने की कोशिश की। – twotwotwo

+0

एक अतिरिक्त बात: एम्बेडिंग दृष्टिकोण विरासत की तरह थोड़ा अधिक है, है ना? आपको एम्बेडेड स्ट्रक्चर के किसी भी फ़ील्ड और विधियां मिलती हैं, और आप इसका इंटरफ़ेस का उपयोग कर सकते हैं ताकि किसी भी सुपरस्ट्रक्चर इंटरफेस के सेट को फिर से कार्यान्वित किए बिना योग्य हो सके। –