Suche…


Objekte erstellen

Im Gegensatz zu vielen anderen Sprachen verfügt Perl nicht über Konstruktoren, die Speicher für Ihre Objekte zuweisen. Stattdessen sollte man eine Klassenmethode schreiben, die sowohl eine Datenstruktur erstellt als auch Daten mit Daten auffüllt (Sie kennen sie vielleicht als das Konstruktionsmuster Factory Method).

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

Diese Methode kann wie folgt verwendet werden:

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

Immer wenn der Pfeiloperator -> mit Methoden verwendet wird, wird sein linker Operand der angegebenen Argumentliste vorangestellt. @_ in new enthält also Werte ('Point', 1, 2.5) .

Es gibt nichts Besonderes im new Namen. Sie können die Factory-Methoden nach Belieben aufrufen.

In Hashes ist nichts Besonderes. Sie können dasselbe auf folgende Weise tun:

package Point;
use strict;

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

Im Allgemeinen kann jede Referenz ein Objekt sein, sogar eine Skalarreferenz. In den meisten Fällen sind Hashes jedoch die bequemste Art, Objektdaten darzustellen.

Klassen definieren

Im Allgemeinen sind Klassen in Perl nur Pakete. Sie können wie üblich Daten und Methoden enthalten.

package Point;
use strict;

my $CANVAS_SIZE = [1000, 1000];

sub new {
    ...
}

sub polar_coordinates {
    ...
}

1;

Es ist wichtig zu beachten, dass die in einem Paket deklarierten Variablen Klassenvariablen und keine Objektvariablen sind. Das Ändern einer Variablen auf Paketebene wirkt sich auf alle Objekte der Klasse aus. Informationen zum Speichern objektspezifischer Daten finden Sie unter "Objekte erstellen".

Was Klassenpakete spezifisch macht, ist der Pfeiloperator -> . Es kann nach einem bloßen Wort verwendet werden:

Point->new(...);

oder nach einer skalaren Variablen (normalerweise eine Referenz):

my @polar = $point->polar_coordinates;

Was sich links vom Pfeil befindet, wird der angegebenen Argumentliste der Methode vorangestellt. Zum Beispiel nach dem Anruf

Point->new(1, 2);

array @_ in new enthält drei Argumente: ('Point', 1, 2) .

Pakete, die Klassen repräsentieren, sollten diese Konvention berücksichtigen und erwarten, dass alle ihre Methoden ein zusätzliches Argument haben.

Vererbung und Methodenauflösung

Um eine Klasse zu einer Unterklasse einer anderen Klasse zu machen, verwenden Sie das parent Pragma:

package Point;
use strict;
...
1;

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

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

Perl erlaubt Mehrfachvererbung:

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

Bei der Vererbung geht es um die Auflösung, welche Methode in einer bestimmten Situation aufgerufen werden soll. Da reines Perl keine Regeln für die zum Speichern von Objektdaten verwendete Datenstruktur vorschreibt, hat die Vererbung damit nichts zu tun.

Betrachten Sie die folgende Klassenhierarchie:

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;

Die Methodenauflösung funktioniert wie folgt:

  1. Der Startpunkt wird durch den linken Operanden des Pfeiloperators festgelegt.

    • Wenn es ein bloßes Wort ist:

      Point2D->new(...);
      

      ... oder eine skalare Variable, die eine Zeichenfolge enthält:

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

      ... dann ist der Ausgangspunkt das Paket mit dem entsprechenden Namen ( Point2D in beiden Beispielen).

    • Wenn der linke Operand eine skalare Variable ist, die eine gesegnete Referenz enthält:

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

      dann ist der Startpunkt die Klasse der Referenz (wieder Point2D ). Mit dem Pfeiloperator können keine Methoden für nicht gesetzte Referenzen aufgerufen werden .

  2. Wenn der Startpunkt die gewünschte Methode enthält, wird sie einfach aufgerufen.

    Da also Point2D::new existiert,

    Point2D->new(...);
    

    werde es einfach anrufen.

  3. Wenn der Startpunkt nicht die erforderliche Methode enthält, wird die Tiefensuche in den parent Klassen durchgeführt. Im obigen Beispiel lautet die Suchreihenfolge wie folgt:

    • Point2D
    • Point (erstes übergeordnetes Point2D von Point2D )
    • GeometryObject (übergeordnetes Point )
    • PlanarObject (zweites übergeordnetes Point2D von Point2D )

    Zum Beispiel im folgenden Code:

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

    Die Methode, die aufgerufen wird, ist GeometryObject::transpose , auch wenn sie in PlanarObject::transpose überschrieben würde.

  4. Sie können den Startpunkt explizit festlegen.

    Im vorherigen Beispiel können Sie PlanarObject::transpose explizit wie PlanarObject::transpose aufrufen:

    my $point = Point2D->new(...);
    $point->PlanarObject::transpose(...);
    
  5. In ähnlicher Weise führt SUPER:: die Methodensuche in übergeordneten Klassen der aktuellen Klasse durch.

    Zum Beispiel,

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

    ruft im Lauf der Point2D::new Ausführung Point::new auf.

Klassen- und Objektmethoden

In Perl ist der Unterschied zwischen Klassenmethoden (statisch) und Objektmethoden (Instanz) nicht so groß wie in einigen anderen Sprachen, aber er existiert immer noch.

Der linke Operand des Pfeiloperators -> wird das erste Argument der aufzurufenden Methode. Es kann entweder eine Zeichenfolge sein:

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

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

oder eine Objektreferenz:

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

Klassenmethoden sind nur diejenigen, die erwarten, dass ihr erstes Argument eine Zeichenfolge ist, und Objektmethoden erwarten, dass ihr erstes Argument eine Objektreferenz ist.

Klassenmethoden machen normalerweise nichts mit ihrem ersten Argument, bei dem es sich nur um den Namen der Klasse handelt. Im Allgemeinen wird es nur von Perl selbst für die Methodenauflösung verwendet. Daher kann eine typische Klassenmethode auch für ein Objekt aufgerufen werden:

my $width = Point->canvas_width;

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

Obwohl diese Syntax zulässig ist, ist sie oft irreführend, daher ist es besser, sie zu vermeiden.

Objektmethoden erhalten eine Objektreferenz als erstes Argument, sodass sie die Objektdaten ansprechen können (im Gegensatz zu Klassenmethoden):

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;

Die gleiche Methode kann beide Fälle verfolgen: Wenn sie als Klassen- oder Objektmethode aufgerufen wird:

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

Definieren von Klassen in modernem Perl

Obwohl verfügbar, wird die Definition einer Klasse von Grund auf in modernen Perl nicht empfohlen. Verwenden Sie eines der OO-Hilfssysteme, die mehr Funktionen und Komfort bieten. Zu diesen Systemen gehören:

Elch

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 (Moose-Syntax)

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 Syntax)

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

Klasse :: Tiny

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

Rollen

Eine Rolle in Perl ist im Wesentlichen

  • eine Reihe von Methoden und Attributen welche
  • direkt in eine Klasse gespritzt.

Eine Rolle stellt eine Funktion bereit, die in jede Klasse (die die Rolle beanspruchen soll) zusammengesetzt (oder auf diese angewendet ) werden kann. Eine Rolle kann nicht vererbt werden, kann aber von einer anderen Rolle belegt werden.

Eine Rolle kann auch erfordern , dass Klassen zum Implementieren einiger Methoden verwendet werden, anstatt die Methoden selbst zu implementieren (genau wie Schnittstellen in Java oder C #).

Perl bietet keine integrierte Unterstützung für Rollen, es gibt jedoch CPAN-Klassen, die eine solche Unterstützung bieten.

Elch :: Rolle

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

Rolle :: Tiny

Verwenden Sie diese Option, wenn Ihr OO-System keine Rollen unterstützt (z. B. Class::Accessor oder Class::Tiny ). Unterstützt keine Attribute.

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow