मैंने Document
नामक एक साधारण Moose आधारित कक्षा लिखी है। इस वर्ग में दो विशेषताएं हैं: name
और homepage
।पर्ल/मूस - मैं गतिशील रूप से किसी विधि के विशिष्ट कार्यान्वयन को कैसे चुन सकता हूं?
कक्षा को do_something()
नामक एक विधि प्रदान करने की आवश्यकता है जो homepage
विशेषता के आधार पर विभिन्न स्रोतों (जैसे वेबसाइट या विभिन्न डेटाबेस) से टेक्स्ट पुनर्प्राप्त और लौटाता है।
चूंकि do_something()
के लिए पूरी तरह से अलग कार्यान्वयन का एक बहुत हो जाएगा, मैं उन्हें विभिन्न संकुल/कक्षाओं में करना चाहते हैं और इन कक्षाओं में से प्रत्येक को पता होना चाहिए अगर यह homepage
विशेषता के लिए जिम्मेदार है या अगर यह नहीं है ।
package Role::Fetcher;
use Moose::Role;
requires 'do_something';
has url => (
is => 'ro',
isa => 'Str'
);
package Role::Implementation;
use Moose::Role;
with 'Role::Fetcher';
requires 'responsible';
एक वर्ग जो do_something()
के लिए एक डिफ़ॉल्ट implmenentation प्रदान करता है और आमतौर पर इस्तेमाल किया तरीकों (एक HTTP GET अनुरोध की तरह) Document::Fetcher
कहा जाता है:
package Document::Fetcher;
use Moose;
use LWP::UserAgent;
with 'Role::Fetcher';
has ua => (
is => 'ro',
isa => 'Object',
required => 1,
default => sub { LWP::UserAgent->new }
);
sub do_something {'called from default implementation'}
sub get {
my $r = shift->ua->get(shift);
return $r->content if $r->is_success;
# ...
}
मेरे दृष्टिकोण अब तक दो भूमिकाएं शामिल और विशिष्ट कार्यान्वयन जो responsible()
नामक विधि के माध्यम से अपनी ज़िम्मेदारी निर्धारित करते हैं:
package Document::Fetcher::ImplA;
use Moose;
extends 'Document::Fetcher';
with 'Role::Implementation';
sub do_something {'called from implementation A'}
sub responsible { return 1 if shift->url =~ m#foo#; }
package Document::Fetcher::ImplB;
use Moose;
extends 'Document::Fetcher';
with 'Role::Implementation';
sub do_something {'called from implementation B'}
sub responsible { return 1 if shift->url =~ m#bar#; }
मेरे Document
वर्ग इस तरह दिखता है:
package Document;
use Moose;
has [qw/name homepage/] => (
is => 'rw',
isa => 'Str'
);
has fetcher => (
is => 'ro',
isa => 'Document::Fetcher',
required => 1,
lazy => 1,
builder => '_build_fetcher',
handles => [qw/do_something/]
);
sub _build_fetcher {
my $self = shift;
my @implementations = qw/ImplA ImplB/;
foreach my $i (@implementations) {
my $fetcher = "Document::Fetcher::$i"->new(url => $self->homepage);
return $fetcher if $fetcher->responsible();
}
return Document::Fetcher->new(url => $self->homepage);
}
अभी इस एकदम सही ढंग से काम करता है। अगर मैं निम्नलिखित कोड फोन:
foreach my $i (qw/foo bar baz/) {
my $doc = Document->new(name => $i, homepage => "http://$i.tld/");
say $doc->name . ": " . $doc->do_something;
}
मैं उम्मीद आउटपुट प्राप्त:
foo: called from implementation A
bar: called from implementation B
baz: called from default implementation
लेकिन वहाँ इस कोड के साथ कम से कम दो मुद्दे हैं:
मैं एक रखने की जरूरत है
_build_fetcher
में सभी ज्ञात कार्यान्वयन की सूची। मैं एक तरीका पसंद करूंगा जहां कोड नामस्थानDocument::Fetcher::
के नीचे स्वचालित रूप से प्रत्येक लोड मॉड्यूल/कक्षा से चयन करेगा। या शायद इस तरह के प्लगइन "रजिस्टर" करने का एक बेहतर तरीका है?फिलहाल पूरा कोड थोड़ा फूला हुआ दिखता है। मुझे यकीन है कि लोगों ने पहले इस तरह की प्लगइन प्रणाली लिखी है। MooseX में कोई चीज़ नहीं है जो वांछित व्यवहार प्रदान करता है?
मैंने GRASP जैसे सिद्धांतों के बारे में भी सोचा नहीं है। किसी भी तरह से मैंने ऐसा किया जो मूस के साथ "एक अच्छा तरीका" प्रतीत होता था। अब जब आपने उनका उल्लेख किया है तो यह एक अमूर्त कारखाने का उपयोग करने के लिए निश्चित रूप से सही अर्थ बनाता है। मुझे अभी भी यकीन नहीं है कि प्रत्येक भूमिका कैसे पंजीकृत करें। क्या इसे किसी प्रकार की सिंगलटन कक्षा की आवश्यकता नहीं होगी? अभी मैं कुछ हद तक हैकी समाधान का उपयोग कर रहा हूं: '% दस्तावेज़ :: Fetcher ::' की जांच कर रहा हूं। –
@ सेबेस्टियनस्टम्पफ आपको चीजों को जटिल बनाने की ज़रूरत नहीं है क्योंकि मूस लोगों के पास क्लास डेटा के खिलाफ दार्शनिक क्रोध है, और न ही आपको वैश्विक चर के लिए पहुंचना है। सामान्य encapsulation अभी भी काम करता है। – Schwern
मैंने इसे अंत में कारक के मेटा क्लास में एक विशेषता जोड़कर थोड़ा और अधिक "मूसिश" हल किया जिसमें 'fetrayhers 'नामक' ArrayRef [Str] 'विशेषता है। तो मैं सिर्फ '__PACKAGE __-> मेटा-> fetchers-> add' कह सकता हूं। :-) –