खोज…


वस्तुओं का निर्माण

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

package Point;
use strict;

sub new {
    my ($class, $x, $y) = @_;
    my $self = { x => $x, y => $y }; # store object data in a hash
    bless $self, $class;             # bind the hash to the class
    return $self;
}

इस विधि का उपयोग इस प्रकार किया जा सकता है:

my $point = Point->new(1, 2.5);

जब भी तीर ऑपरेटर -> विधियों के साथ प्रयोग किया जाता है, तो इसके बाएं ऑपरेंड को दिए गए तर्क सूची में रखा जाता है। तो, new में @_ में मान होंगे ('Point', 1, 2.5)

new नाम में कुछ खास नहीं है। आप जैसे चाहें फ़ैक्टरी विधियों को कॉल कर सकते हैं।

हैश में कुछ खास नहीं है। आप निम्न तरीके से ऐसा कर सकते हैं:

package Point;
use strict;

sub new {
    my ($class, @coord) = @_;
    my $self = \@coord;
    bless $self, $class;
    return $self;
}

सामान्य तौर पर, कोई भी संदर्भ एक वस्तु हो सकता है, यहां तक कि एक स्केलर संदर्भ भी। लेकिन सबसे अधिक बार, हैश ऑब्जेक्ट डेटा का प्रतिनिधित्व करने का सबसे सुविधाजनक तरीका है।

परिभाषित करने वाली कक्षाएं

सामान्य तौर पर, पर्ल में कक्षाएं सिर्फ पैकेज हैं। वे सामान्य पैकेज के रूप में डेटा और विधियाँ शामिल कर सकते हैं।

package Point;
use strict;

my $CANVAS_SIZE = [1000, 1000];

sub new {
    ...
}

sub polar_coordinates {
    ...
}

1;

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

क्लास पैकेज क्या विशिष्ट बनाता है, तीर ऑपरेटर है -> । इसका इस्तेमाल नंगे शब्द के बाद किया जा सकता है:

Point->new(...);

या एक स्केलर चर के बाद (आमतौर पर एक संदर्भ पकड़े):

my @polar = $point->polar_coordinates;

तीर के बाईं ओर क्या विधि की दी गई तर्क सूची के लिए तैयार है। उदाहरण के लिए, कॉल के बाद

Point->new(1, 2);

सरणी @_ में new में तीन तर्क होंगे: ('Point', 1, 2)

कक्षाओं का प्रतिनिधित्व करने वाले पैकेजों को इस सम्मेलन को ध्यान में रखना चाहिए और उम्मीद करनी चाहिए कि उनके सभी तरीकों में एक अतिरिक्त तर्क होगा।

वंशानुक्रम और तरीके संकल्प

एक कक्षा को दूसरी कक्षा का उपवर्ग बनाने के लिए, parent प्रज्ञा का उपयोग करें:

package Point;
use strict;
...
1;

package Point2D;
use strict;
use parent qw(Point);
...
1;

package Point3D;
use strict;
use parent qw(Point);
...
1;

पर्ल कई उत्तराधिकार के लिए अनुमति देता है:

package Point2D;
use strict;
use parent qw(Point PlanarObject);
...
1;

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

निम्नलिखित वर्ग पदानुक्रम पर विचार करें:

package GeometryObject;
use strict;

sub transpose { ...}

1;

package Point;
use strict;
use parent qw(GeometryObject);

sub new { ... };

1;

package PlanarObject;
use strict;
use parent qw(GeometryObject);

sub transpose { ... }

1;

package Point2D;
use strict;
use parent qw(Point PlanarObject);

sub new { ... }

sub polar_coordinates { ... }

1;

विधि संकल्प निम्नानुसार काम करता है:

  1. प्रारंभिक बिंदु तीर ऑपरेटर के बाएं ऑपरेंड द्वारा परिभाषित किया गया है।

    • यदि यह एक नंगे शब्द है:

      Point2D->new(...);
      

      ... या एक स्केलर चर एक स्ट्रिंग पकड़े:

      my $class = 'Point2D';
      $class->new(...);
      

      ... फिर शुरुआती बिंदु संबंधित नाम (दोनों उदाहरणों में Point2D ) के साथ पैकेज है।

    • यदि बाईं संकार्य एक अदिश चर है जो एक धन्य संदर्भ है:

      my $point = {...};
      bless $point, 'Point2D'; # typically, it is encapsulated into class methods
      my @coord = $point->polar_coordinates;
      

      फिर शुरुआती बिंदु संदर्भ का वर्ग है (फिर से, Point2D )। तीर ऑपरेटर बेचारा संदर्भ के लिए तरीकों कॉल करने के लिए इस्तेमाल नहीं किया जा सकता है।

  2. यदि प्रारंभिक बिंदु में आवश्यक विधि है, तो इसे बस कहा जाता है।

    इस प्रकार, चूंकि Point2D::new मौजूद है,

    Point2D->new(...);
    

    बस इसे कॉल करेंगे।

  3. यदि प्रारंभिक बिंदु में आवश्यक विधि नहीं है, तो parent कक्षाओं में गहराई-पहली खोज की जाती है। उपरोक्त उदाहरण में, खोज क्रम निम्नानुसार होगा:

    • Point2D
    • Point (के पहले माता-पिता Point2D )
    • GeometryObject ( Point ऑफ पैरेंट)
    • PlanarObject (के दूसरे माता पिता Point2D )

    उदाहरण के लिए, निम्नलिखित कोड में:

    my $point = Point2D->new(...);
    $point->transpose(...);
    

    विधि जिसे कहा जाएगा, वह है GeometryObject::transpose , भले ही इसे PlanarObject::transpose में ओवरराइड किया जाएगा।

  4. आप प्रारंभिक बिंदु को स्पष्ट रूप से सेट कर सकते हैं।

    पिछले उदाहरण में, आप स्पष्ट रूप से PlanarObject::transpose कॉल कर सकते हैं PlanarObject::transpose ऐसा PlanarObject::transpose करें:

    my $point = Point2D->new(...);
    $point->PlanarObject::transpose(...);
    
  5. इसी तरह से, SUPER:: वर्तमान कक्षा के मूल वर्गों में विधि खोज करता है।

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

    package Point2D;
    use strict;
    use parent qw(Point PlanarObject);
    
    sub new {
        (my $class, $x, $y) = @_;
        my $self = $class->SUPER::new;
        ...
    }
    
    1;
    

    Point::new को कॉल करेगा: Point::new के पाठ्यक्रम में Point2D::new निष्पादन।

क्लास और ऑब्जेक्ट के तरीके

पर्ल में, क्लास (स्थिर) और ऑब्जेक्ट (उदाहरण) के बीच का अंतर इतना मजबूत नहीं है जितना कि कुछ अन्य भाषाओं में, लेकिन यह अभी भी मौजूद है।

तीर ऑपरेटर का बायाँ संचालक -> कहा जाने वाला विधि का पहला तर्क है। यह या तो एक स्ट्रिंग हो सकती है:

# the first argument of new is string 'Point' in both cases
Point->new(...);

my $class = 'Point';
$class->new(...);

या एक वस्तु संदर्भ:

# reference contained in $point is the first argument of polar_coordinates
my $point = Point->new(...);
my @coord = $point->polar_coordinates;

क्लास मेथड वही होते हैं जो अपने पहले तर्क को एक स्ट्रिंग होने की उम्मीद करते हैं, और ऑब्जेक्ट मेथड वे होते हैं जो उम्मीद करते हैं कि उनका पहला तर्क ऑब्जेक्ट रेफरेंस हो।

क्लास के तरीके आमतौर पर अपने पहले तर्क के साथ कुछ भी नहीं करते हैं, जो सिर्फ क्लास का एक नाम है। आमतौर पर, इसका उपयोग केवल पर्ल ही विधि संकल्प के लिए करते हैं। इसलिए, एक सामान्य वर्ग विधि को किसी वस्तु के लिए भी कहा जा सकता है:

my $width = Point->canvas_width;

my $point = Point->new(...);
my $width = $point->canvas_width;

हालांकि इस वाक्यविन्यास की अनुमति है, यह अक्सर भ्रामक है, इसलिए इससे बचना बेहतर है।

ऑब्जेक्ट विधियाँ पहले तर्क के रूप में एक ऑब्जेक्ट संदर्भ प्राप्त करती हैं, इसलिए वे ऑब्जेक्ट डेटा (वर्ग विधियों के विपरीत) को संबोधित कर सकते हैं:

package Point;
use strict;

sub polar_coordinates {
    my ($point) = @_;
    my $x = $point->{x};
    my $y = $point->{y};
    return (sqrt($x * $x + $y * $y), atan2($y, $x));
}

1;

एक ही विधि दोनों मामलों को ट्रैक कर सकती है: जब इसे कक्षा या ऑब्जेक्ट विधि के रूप में कहा जाता है:

sub universal_method {
    my $self = shift;
    if (ref $self) {
        # object logic
        ...
    }
    else {
        # class logic
        ...
    }
}

आधुनिक पर्ल में कक्षाएं परिभाषित करना

हालांकि उपलब्ध है, आधुनिक पर्ल में एक वर्ग को खरोंच से परिभाषित करने की अनुशंसा नहीं की जाती है। हेल्पर OO सिस्टम में से एक का उपयोग करें जो अधिक सुविधाएँ और सुविधा प्रदान करता है। इन प्रणालियों में से हैं:

  • Moose - पर्ल 6 ओओ डिजाइन से प्रेरित है

  • Class::Accessor - मूस के लिए एक हल्का विकल्प

  • Class::Tiny - वास्तव में न्यूनतम वर्ग बिल्डर

मूस

package Foo;
use Moose;

has bar => (is => 'ro');                 # a read-only property
has baz => (is => 'rw', isa => 'Bool');  # a read-write boolean property

sub qux {
    my $self = shift;
    my $barIsBaz = $self->bar eq 'baz';  # property getter
    $self->baz($barIsBaz);               # property setter
}

क्लास :: एक्सेसर (Moose सिंटैक्स)

package Foo;
use Class::Accessor 'antlers';

has bar => (is => 'ro');                 # a read-only property
has baz => (is => 'rw', isa => 'Bool');  # a read-write property (only 'is' supported, the type is ignored)

क्लास :: एक्सेसर (मूल सिंटैक्स)

package Foo;
use base qw(Class::Accessor);

Foo->mk_accessors(qw(bar baz));  # some read-write properties
Foo->mk_accessors(qw(qux));      # a read-only property

कक्षा :: टिनी

package Foo;
use Class::Tiny qw(bar baz);  # just props

भूमिकाएँ

पर्ल में एक भूमिका अनिवार्य रूप से है

  • तरीकों और विशेषताओं का एक सेट जो
  • सीधे कक्षा में इंजेक्ट किया गया।

एक भूमिका कार्यक्षमता का एक टुकड़ा प्रदान करती है जिसे किसी भी वर्ग (जिसे भूमिका का उपभोग करने के लिए कहा जाता है) में रचना (या लागू ) की जा सकती है। एक भूमिका को विरासत में नहीं दिया जा सकता है लेकिन किसी अन्य भूमिका के द्वारा उपभोग किया जा सकता है।

एक भूमिका के लिए कुछ तरीकों को लागू करने के लिए उपभोग्य वर्गों की आवश्यकता हो सकती है, ताकि वे स्वयं विधियों को लागू कर सकें (जैसे जावा या C # में इंटरफेस)।

पर्ल के पास भूमिकाओं के लिए अंतर्निहित समर्थन नहीं है लेकिन सीपीएएन वर्ग हैं जो इस तरह का समर्थन प्रदान करते हैं।

मूस :: भूमिका

package Chatty;
use Moose::Role;

requires 'introduce';  # a method consuming classes must implement

sub greet {            # a method already implemented in the role
    print "Hi!\n";
}


package Parrot;
use Moose;

with 'Chatty';

sub introduce {
    print "I'm Buddy.\n";
}

भूमिका :: टिनी

यदि आपका OO सिस्टम भूमिकाओं के लिए सहायता प्रदान नहीं करता है (जैसे Class::Accessor या Class::Tiny )। विशेषताओं का समर्थन नहीं करता है।

package Chatty;
use Role::Tiny;

requires 'introduce';  # a method consuming classes must implement

sub greet {            # a method already implemented in the role
    print "Hi!\n";
}

package Parrot;
use Class::Tiny;
use Role::Tiny::With;

with 'Chatty';

sub introduce {
    print "I'm Buddy.\n";
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow