2010-06-08 13 views
5

के लिए अपनी कक्षा के बजाय एक क्लास क्लास इंस्टेंस कैसे लौटाता है, मैं एक सामान्य वर्ग बनाना चाहता हूं, जिसका निर्माता इस सामान्य वर्ग का उदाहरण नहीं लौटाएगा, बल्कि एक समर्पित बाल वर्ग का उदाहरण देगा।मॉइज़ पॉलिमॉर्फिज्म

चूंकि मूस स्वचालित ऑब्जेक्ट बिल्डिंग करता है, मुझे यह समझ में नहीं आता कि यह कुछ संभव है, और मूस सिंटैक्स के साथ मूस क्लास कैसे बनाएं और यह व्यवहार करें।

जैसे: उपयोगकर्ता पूछते हैं: $file = Repository->new(uri=>'sftp://blabla') .... और जरूरत पता करने के लिए बिना, एक `भंडार :: _ Sftp`` उदाहरण

उपयोगकर्ता $file का प्रयोग करेंगे जैसे कि यह एक भंडार उदाहरण है लौटा दिया जाता है असली उपवर्ग (बहुरूपता)

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

उत्तर

6

new बिल्डर बनाता है। आप वास्तव में निर्मित ऑब्जेक्ट को वापस करने के लिए कुछ अन्य विधि चाहते हैं।

class RepositoryBuilder { 
    has 'allow_network_repositories' => (
     is  => 'ro', 
     isa  => 'Bool', 
     required => 1, 
    ); 

    method build_repository(Uri $url) { 
     confess 'network access is not allowed' 
      if $url->is_network_url && !$self->allow_network_repositories; 

     my $class = $self->determine_class_for($url); # Repository::Whatever 
     return $class->new(url => $url); 
    } 
    } 

    role Repository { <whatever } 

    class Repository::File with Repository {} 
    class Repository::HTTP with Repository {} 

यहाँ, बिल्डर और निर्मित वस्तु भिन्न हैं:

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

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

यहां हम निर्माता द्वारा बनाए गए निर्माता का उपयोग करते हैं। हैं, कहते हैं, आप नहीं स्पर्श करने के लिए नेटवर्क हैं:

my $b = RepositoryBuilder->new(allow_network_repositories => 0); 
$b->build_repository('http://google.com/'); # error 
$b->build_repository('file:///home/whatever'); # returns a Repository::Foo 

लेकिन अगर आप कार्य करें:

my $b = RepositoryBuilder->new(allow_network_repositories => 1); 
$b->build_repository('http://google.com/'); # Repository::HTTP 

अब आप एक बिल्डर है कि वस्तुओं को अपनी इच्छानुसार बनाता है, आपको बस इन ऑब्जेक्ट्स को अन्य कोड में उपयोग करने की आवश्यकता है। तो पहेली में अंतिम टुकड़ा अन्य कोड में "किसी भी प्रकार का रिपोजिटरी ऑब्जेक्ट" का जिक्र कर रहा है। यही कारण है कि आसान है, आप isa के बजाय does का उपयोग करें:

class SomethingThatHasARepository { 
    has 'repository' => (
     is  => 'ro', 
     does  => 'Repository', 
     required => 1, 
    ); 
} 

और बस हो गया।

+0

mmh पर एक नोट जोड़ा ... मुझे इस भूमिका की बात समझने दो, मूस दस्तावेज़ों पर वापस ... इसके अलावा, मेरे बारे में मेरा पहला विचार, क्योंकि मैं बस मूस से शुरू करता हूं , क्या मूस –

+0

@alex की तुलना में खराब मूस करना अभी भी बेहतर है या नहीं: यदि आप मूस :: मैनुअल :: * में उदाहरणों का पालन करते हैं, तो आप कठिनाई के बिना मूस की अधिकांश सुविधाओं का उपयोग कर सकते हैं। यह केवल तभी होता है जब आप 'मेटा' का उपयोग शुरू करते हैं कि चीजें पागल हो जाती हैं :) – Ether

+0

ठीक है, समझ में आया, लेकिन मैं सूक्ष्म मतभेदों के बारे में उत्सुक हूं: ए) सभी मूल विशेषताओं के साथ एक मूस बेस क्लास 'रिपोजिटरी'; विशिष्ट मूस वर्ग 'रिपोजिटरी :: _ एसएफटीपी' जो "विस्तार"/आधार वर्ग विरासत में आता है; एक मूस (या नहीं) कारखाना 'रिपोजिटरीबिल्डर', मुझे विशेष वर्ग का एक उदाहरण बनाने के तरीके के साथ, जिसे 'रिपोजिटरी' के रूप में अज्ञात रूप से छेड़छाड़ की जा सकती है। बी) एक जैसा ही), लेकिन बेस क्लास की बजाय भूमिका के साथ <- जो आपने प्रस्तावित किया है, है ना? सी) और डी) मूसएक्स :: सार फैक्ट्री या मूसएक्स :: एबीसी, लेकिन ये डिफ़ॉल्ट रूप से उपलब्ध नहीं हैं (मैं रेफरी के लिए सेंटोस 5 लेता हूं) –

2

नहीं (सीधे नहीं)। मूस में सामान्य रूप से, CLASS->new पर कॉल करते हुए जहां क्लास आईएसए मूस :: ऑब्जेक्ट क्लास का एक उदाहरण लौटाएगा।

क्या आप अधिक विस्तार से वर्णन कर सकते हैं कि आप क्या हासिल करने की कोशिश कर रहे हैं, और आप ऐसा क्यों सोचते हैं जो आप चाहते हैं? आप शायद फैक्टरी कक्षा बनाना चाहते हैं - जब आप उस पर कोई विधि कॉल करते हैं, तो यह उचित वर्ग के कन्स्ट्रक्टर को कॉल करेगा और उस वस्तु को वापस लौटाएगा, बिना किसी विशेष प्रकार से आप चिंतित होने के बिना:

package MyApp::Factory::Repository; 

sub getFactory 
{ 
    my ($class, %attrs); 

    # figure out what the caller wants, and decide what type to return 
    $class ||= 'Repository::_Sftp'; 
    return $class->new(attr1 => 'foo', attr2 => 'bar', %attrs); 
} 

my $file = MyApp::Factory::Repository->getFactory(uri=>'sftp://blabla'); 
+0

यह मेरी तरह की तरह है, जिसे मैं कक्षा :: एक्सेसर के साथ भी उपयोग कर रहा था। और एक प्रश्न में मैंने कल सी के बारे में पूछा: ए का उल्लेख है कि मुझे मूस (उत्तर इस मामले से संबंधित नहीं) का प्रयास करना चाहिए। इसलिए मैं अपने कारखाने को "moosify" करने की कोशिश कर रहा था। उद्देश्य के लिए, मैंने मुख्य प्रश्न –

संबंधित मुद्दे