2009-11-21 10 views
5

हमारे वर्गों में हमारे पास एक पैटर्न है जहां हम गणना मूल्य का प्रतिनिधित्व करने के लिए एक विशेषता बनाते हैं। स्पष्ट कारणों से हम गणना मूल्य को कैश करना चाहते हैं और उसके बाद अंतर्निहित मानों में से एक बदलते समय कैश को अमान्य कर देना चाहते हैं।मूस: विशेषता मान बदलते समय गणना के कैश किए गए परिणाम समाप्त हो रहे हैं?

तो हम वर्तमान में इस है:

package FooBar; 
use Moose; 

has 'foo' => (
     accessor => { 
      'foo' => sub { 
       my $self = shift; 
       if (@_ > 0) { 
        # writer 
        $self->{foo} = $_[0]; 

     # reset fields that are dependant on me 
     $self->{bar} = undef; 
       } 
       # reader part; 
       return $self->{foo}; 
      } 
     } 
    ); 

has 'bar' => (
     accessor => { 
      'bar' => sub { 
       my $self = shift; 
       if (@_ > 0) { 
        # writer 
        $self->{bar} = $_[0]; 
       } 
       # reader part; 
       $self->{bar} = calculate_bar($self->foo, $self->baz) 
         if (not defined($self->{bar})); 
       return $self->{bar}; 
      } 
     } 
    ); 

sub calculate_bar { ... } 

यह लंबे हाथ विधि बहुत कठिन और त्रुटि प्रवण हो रही है जब परिकलित मानों अन्य गणना मूल्यों पर निर्भर।

क्या पर निर्भर गुणों की निगरानी करने के लिए 'बार' के लिए एक स्मार्ट/सरल तरीका है, यह 'foo' बना रहा है, जो इस पर निर्भर है? मैं हैश सदस्य पहुंच के माध्यम से सेटिंग बार से कैसे बच सकता हूं?

उत्तर

5

मुझे लगता है कि यह भी संभव है कि आप अपने आप पर यह कठिन बना रहे हैं एक गुण, आलसी के साथ अंतर्निहित Memoization का उपयोग करके जब तुम सिर्फ कर सकता है Memoization स्पष्ट करने के बाद अपना पूरे कार्यक्रम को अधिक पारदर्शी

has [qw/foo bar baz/] => (isa => 'Value', is => 'rw'); 

use Memoize; 
memoize('_memoize_this'); 

sub old_lazy_attr { 
    my $self = shift; 
    _memoize_this($self->attr1, $self->attr2, $self->attr3); 
} 

sub _memoize_this { 
    my @args = @_; 
    # complex stuff 
    return $result 
} 

cpan के Memoize जानकारी और आंतरिक कैश के नियंत्रण के लिए देखें, यह भी याद रखें कि एक Memoized कार्य वस्तु की स्थिति पर निर्भर नहीं हो सकता है। तो तर्क स्पष्ट रूप से में पारित किया जाना चाहिए।

+0

एचएम। मुझे ऑब्जेक्ट डेटा कैश करने के लिए Memoize का उपयोग करके अपने सिर को प्राप्त करने में समस्याएं हैं I क्या होता है यदि इस वर्ग के प्रत्येक उदाहरण के अलग-अलग मूल्य हैं? याद रखें उन्हें इस तथ्य के बावजूद हमेशा के लिए कैश करेगा जब ऑब्जेक्ट नष्ट हो जाए, तो वे अब उपयोगी नहीं होंगे, है ना? जिसका मतलब एक सतत ऐप में है (और यह वास्तव में मूस का उपयोग करने के लिए एकमात्र समझदार जगह है) आप संभावित रूप से एक विशाल, बेकार कैश विकसित करने जा रहे हैं। नहीं? बेशक , आप कर सकते हैं सामान मैन्युअल समाप्त हो रही (मुझे लगता है कि!), लेकिन यह है कि छोटे से लाभ के लिए ऊपर मूस/आलसी उदाहरण के ऊपर जिस तरह से अधिक जटिलता है, .. – Dan

+1

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

+1

मैंने इसे उत्तर के रूप में चुना क्योंकि यह कोड को काफी सरल बनाता है, जो मैं वास्तव में प्रयास कर रहा था। तथ्य यह है कि गणना का परिणाम ऑब्जेक्ट में संग्रहीत नहीं है, यह मेरे वर्तमान कार्यान्वयन के लिए कोई समस्या नहीं है। धन्यवाद इवान कैरोल। – clscott

11

यदि मैं आपको सही ढंग से समझता हूं, तो आप triggers का उपयोग कर सकते हैं जब कोई सेट सेट हो।

has 'foo' => (
    is  => 'rw', 
    trigger => sub{ 
     my ($self) = @_; 
     $self->clear_bar; 
    } 
); 

has 'bar' => (
    is  => 'rw', 
    clearer => 'clear_bar', 
    lazy => 1, 
    default => sub{ 
     my ($self) = @_; 
     return calculate_bar(...); 
    } 
); 

तो, $obj->foo($newvalue) के माध्यम से foo के लिए किसी भी लेखन का कारण होगा bar, हटाए जाने की और अगले उपयोग पर निर्मित: यहाँ एक उदाहरण है।

+1

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

+2

यह एक रखरखाव परिप्रेक्ष्य से पीछे भी है; बार-निर्भर-ऑन-फू तर्कसंगत रूप से बार की संपत्ति है, foo – ysth

+0

यह एक मूस-वाई तरीका और एक अच्छा जवाब नहीं है, लेकिन मैं किसी भी अतिरिक्त मूस आधारित कोड को काटने में सबसे खुश था जो अभी व्यापार तर्क के रास्ते में आया । धन्यवाद दान। – clscott

0

क्या यह काम करेगा?

#!/usr/bin/perl 

package Test; 

use Modern::Perl; 
use Moose; 

has a => (is => 'rw', isa => 'Str', trigger => \&change_a); 
has b => (is => 'rw', isa => 'Str', trigger => \&change_b); 
has c => (is => 'rw', isa => 'Str'); 

sub change_a 
{ 
    my $self = shift; 
    say 'update b'; 
    $self->b($self->a . ', bar'); 
} 

sub change_b 
{ 
    my $self = shift; 
    say 'update c'; 
} 

package main; 

my $test = Test->new->a('Foo'); 

आउटपुट:

$ perl test.pl 
update b 
update c 
+1

मुझे यकीन नहीं है कि आपको क्यों लगता है कि वह बी को सेट करना चाहता है, ए से। लेकिन यह बनाने में परिपत्र ट्रिगर्स का आपदा है। चूंकि आप इसे मेटा के बजाए मूस द्वारा प्रदान किए गए सार्वजनिक इंटरफेस के माध्यम से सेट कर रहे हैं, तो सेटर के माध्यम से बी में एक आकस्मिक परिवर्तन से इसके ट्रिगर को ट्रिगर करने का कारण बन जाएगा ... सार्वजनिक इंटरफ़ेस का उपयोग करके ट्रिगर्स के माध्यम से विशेषताओं को सेट करना एक बुरा विचार है। –

+0

'$ a' से' $ b' सेट करना यह कहने का एक तरीका था कि वह गणना मान ('$ b') अपडेट कर सकता है जब मास्टर मानों में से एक (' $ a') में परिवर्तन होता है। और मुझे नहीं लगता कि अगर वह गणना की गई संपत्तियों को अपडेट करना चाहता है तो एक ट्रिगर चक्र होगा। ऐसा हो सकता है कि मुझे बस आपका तर्क न मिले - उदाहरण है? – zoul

+2

(लेकिन निश्चित रूप से यह समाधान उपर्युक्त लोगों की तुलना में भी बदतर है, यह आलसी '' b' पुन: गणना नहीं करता है।) – zoul

0

मैंने मूस आंतरिक और मेटा ऑब्जेक्ट प्रोटोकॉल में चारों ओर कोई पोकिंग नहीं किया है, लेकिन मुझे लगता है कि यह करने का यह अच्छा समय है।

तुम इतनी है कि जब आप के रूप में

has 'foo' =>(); 
has 'bar' => ( 
    depends_on => [qw(foo)], 
    lazy => \&calculate_bar, 
); 

के रूप में आप ऊपर निर्दिष्ट कोड पीढ़ी चरण foo और bar विशेषताओं के लिए कोड बनाता है एक विशेषता निर्दिष्ट कोड पीढ़ी पैच करने के लिए चाहते हैं।

यह कैसे करें पाठक को एक अभ्यास छोड़ दिया जाता है। अगर मुझे कोई सुराग था, तो मैं आपको एक शुरुआत देने की कोशिश करता था। दुर्भाग्य से, मैं आपको सलाह दे सकता हूं कि "यह एमओपी के लिए एक नौकरी है"।

+0

यह स्वीकार किए गए उत्तर से यह अधिक काम है। यह भी अव्यावहारिक लगता है के रूप में यह परीक्षण और एक MooseX :: मॉड्यूल के रखरखाव, प्लगइन के कुछ प्रकार या मूस को अपने ख़िलाफ़ एक पैच कि कोर में कभी नहीं स्वीकार किया जाएगा की आवश्यकता है। – clscott

+0

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

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