Zoeken…


Objecten maken

In tegenstelling tot veel andere talen heeft Perl geen constructors die geheugen toewijzen aan uw objecten. In plaats daarvan moet men een klassemethode schrijven die zowel een gegevensstructuur maakt als deze met gegevens vult (u kent deze misschien als het ontwerppatroon van de fabrieksmethode).

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;
}

Deze methode kan als volgt worden gebruikt:

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

Telkens wanneer de pijloperator -> wordt gebruikt met methoden, wordt de linkeroperand toegevoegd aan de gegeven argumentenlijst. Dus, @_ in new zal waarden bevatten ('Point', 1, 2.5) .

Er is niets bijzonders in de naam new . U kunt de fabrieksmethoden naar wens gebruiken.

Er is niets bijzonders in hashes. Je zou hetzelfde kunnen doen op de volgende manier:

package Point;
use strict;

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

In het algemeen kan elke verwijzing een object zijn, zelfs een scalaire verwijzing. Maar meestal zijn hashes de handigste manier om objectgegevens weer te geven.

Klassen definiëren

Over het algemeen zijn klassen in Perl slechts pakketten. Ze kunnen gegevens en methoden bevatten, zoals gebruikelijk pakketten.

package Point;
use strict;

my $CANVAS_SIZE = [1000, 1000];

sub new {
    ...
}

sub polar_coordinates {
    ...
}

1;

Het is belangrijk op te merken dat de in een pakket gedeclareerde variabelen klassenvariabelen zijn, geen object (instantie) variabelen. Het wijzigen van een variabele op pakketniveau is van invloed op alle objecten van de klasse. Zie "Objecten maken" voor informatie over het opslaan van objectspecifieke gegevens.

Wat klassepakketten specifiek maakt, is de pijloperator -> . Het kan worden gebruikt na een duidelijk woord:

Point->new(...);

of na een scalaire variabele (meestal met een referentie):

my @polar = $point->polar_coordinates;

Wat zich links van de pijl bevindt, wordt voorafgegaan aan de gegeven argumentenlijst van de methode. Bijvoorbeeld na een oproep

Point->new(1, 2);

array @_ in new zal drie argumenten bevatten: ('Point', 1, 2) .

Pakketten die klassen vertegenwoordigen, moeten rekening houden met deze conventie en verwachten dat al hun methoden één extra argument hebben.

Overerving en resolutie van methoden

Gebruik parent pragma om van een klasse een subklasse van een andere klasse te maken:

package Point;
use strict;
...
1;

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

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

Perl zorgt voor meervoudige overerving:

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

Bij overerving draait alles om resolutie welke methode in een bepaalde situatie moet worden genoemd. Aangezien pure Perl geen regels voorschrijft over de gegevensstructuur die wordt gebruikt om objectgegevens op te slaan, heeft overerving daar niets mee te maken.

Overweeg de volgende klassenhiërarchie:

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;

De methode resolutie werkt als volgt:

  1. Het startpunt wordt bepaald door de linkeroperand van de pijloperator.

    • Als het een kaal woord is:

      Point2D->new(...);
      

      ... of een scalaire variabele met een string:

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

      ... dan is het startpunt het pakket met de bijbehorende naam ( Point2D in beide voorbeelden).

    • Als de linkeroperand een scalaire variabele is met een gezegende referentie:

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

      dan is het startpunt de klasse van de referentie (nogmaals, Point2D ). De pijloperator kan niet worden gebruikt om methoden voor ongetemde verwijzingen aan te roepen.

  2. Als het startpunt de vereiste methode bevat, wordt deze eenvoudigweg aangeroepen.

    Aangezien Point2D::new bestaat,

    Point2D->new(...);
    

    zal het gewoon noemen.

  3. Als het startpunt niet de vereiste methode bevat, wordt diepte-eerste zoekopdracht in de parent klassen uitgevoerd. In het bovenstaande voorbeeld is de zoekvolgorde als volgt:

    • Point2D
    • Point (eerste ouder van Point2D )
    • GeometryObject (ouder van Point )
    • PlanarObject (tweede ouder van Point2D )

    Bijvoorbeeld in de volgende code:

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

    de methode die wordt aangeroepen is GeometryObject::transpose , ook al zou deze worden overschreven in PlanarObject::transpose .

  4. U kunt het startpunt expliciet instellen.

    In het vorige voorbeeld kunt u PlanarObject::transpose als volgt expliciet aanroepen:

    my $point = Point2D->new(...);
    $point->PlanarObject::transpose(...);
    
  5. Op een vergelijkbare manier voert SUPER:: methoden uit in bovenliggende klassen van de huidige klasse.

    Bijvoorbeeld,

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

    roept Point::new in de loop van de Point2D::new uitvoering.

Klasse- en objectmethoden

In Perl is het verschil tussen de methoden class (statisch) en object (instantie) niet zo sterk als in sommige andere talen, maar het bestaat nog steeds.

De linkeroperand van de pijloperator -> wordt het eerste argument van de aan te roepen methode. Het kan een string zijn:

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

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

of een objectverwijzing:

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

Klasse methoden zijn gewoon degenen die verwachten dat hun eerste argument een string is, en object methoden zijn degenen die verwachten dat hun eerste argument een objectverwijzing is.

Class-methoden doen meestal niets met hun eerste argument, wat slechts een naam van de class is. Over het algemeen wordt het alleen door Perl zelf gebruikt voor het oplossen van methoden. Daarom kan ook een typische klassemethode voor een object worden aangeroepen:

my $width = Point->canvas_width;

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

Hoewel deze syntaxis is toegestaan, is deze vaak misleidend, dus het is beter om deze te vermijden.

Objectmethoden ontvangen een objectverwijzing als het eerste argument, zodat ze de objectgegevens kunnen adresseren (in tegenstelling tot klassemethoden):

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;

Dezelfde methode kan beide gevallen volgen: wanneer deze wordt aangeroepen als een klasse of een objectmethode:

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

Definiëren van klassen in moderne Perl

Hoewel beschikbaar, het definiëren van een klasse van de grond wordt niet aanbevolen in de moderne Perl. Gebruik een van de helper OO-systemen die meer functies en gemak bieden. Onder deze systemen zijn:

eland

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
}

Klasse :: Accessor (syntaxis van 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)

Klasse :: Accessor (native syntaxis)

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

Class :: Tiny

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

Rollen

Een rol in Perl is in wezen

  • een set methoden en attributen die
  • rechtstreeks in een klas geïnjecteerd.

Een rol biedt een stuk functionaliteit dat kan worden gecomponeerd in (of toegepast op) elke klasse (waarvan wordt gezegd dat deze de rol verbruikt ). Een rol kan niet worden geërfd, maar kan worden gebruikt door een andere rol.

Een rol kan ook vereisen dat klassen worden gebruikt om sommige methoden te implementeren in plaats van de methoden zelf te implementeren (net als interfaces in Java of C #).

Perl heeft geen ingebouwde ondersteuning voor rollen, maar er zijn CPAN-klassen die dergelijke ondersteuning bieden.

Moose :: Role

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";
}

Rol :: Tiny

Gebruik als uw OO-systeem geen ondersteuning voor rollen biedt (bijvoorbeeld Class::Accessor of Class::Tiny ). Ondersteunt geen attributen.

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow