2015-02-20 2 views
5

So fragte ich mich, ob es einen Unterschied in der Verwendung zwischen einer Perl-Klasse-Methode und einer gewöhnlichen Subroutine von einem Standard-Modul gibt. Gibt es eine Zeit, in der du die eine über der anderen benutzen würdest? In diesem Beispiel gehe ich davon aus, dass in keinem der beiden Module Objektmethoden vorhanden sind.Perl-Modul Klassenmethode vs gewöhnliche Unterroutine

Schnell wenig Hauptklasse hier:

#!/usr/local/bin/perl 

use strict; 
use warnings; 

use Foo; 
use Bar; 

my $arg1 = "blah"; 
my ($str1, $str2); 

$str1 = Foo::subroutine($arg1); 
$str2 = Bar->subroutine($arg1); 
exit(0); 

Paket Foo würde meine gewöhnlichen Unterprogrammaufruf

use strict; 
use warnings; 

package Foo; 

sub subroutine { 
    my $arg = shift; 
    my $string = "Ordinary subroutine arg is $arg\n"; 
    return $string; 
} 
1; 

Paket Bar halten würde meine Klasse Methodenaufruf

use strict; 
use warnings; 

package Bar; 

sub subroutine { 
    my $class = shift; 
    my $arg = shift; 
    my $string = "Class method arg is $arg\n"; 
    return $string; 
} 
1; 

Normalerweise, wenn ich halten Ich schreibe Perl-Code, ich würde einfach die Klassenmethode verwenden (wie beim Bar-Beispiel) le), aber ich fing an, über diese Frage nachzudenken, nachdem ich Code von einem ehemaligen Mitarbeiter gelesen hatte, der die Syntax wie im Foo-Beispiel verwendete. Beide scheinen von Natur aus das Gleiche zu tun, aber es scheint mehr zu geben, als man sieht.

+2

*** Immer *** 'Verwendung strict' und' Verwendung warnings' am Anfang * jeder * Perl Programm, das Sie schreiben, egal wie trivial. Es ist sehr wenig sinnvoll, 'my' ohne' strict' zu verwenden. – Borodin

+0

Vertrau mir, ich tue. Ich habe sie einfach nicht für dieses Beispiel geschrieben, weil es nicht zum zentralen Kern der Frage gehörte. – MeNoSeeGood

+0

Aber Sie haben die Shebang-Linie eingefügt, die bei weitem weniger relevant ist! Bitte schreibe deine Beispiele immer nach best practice: Du wirst weniger oft gezüchtigt, und mehr Leute, die deine Fragen lesen, werden glauben, dass es eine * gute Idee * ist. – Borodin

Antwort

2

Mit einem normalen Unterprogramm ist nichts falsch. Sie tun, was sie entworfen haben, um sehr gut zu machen.

Methoden auf der anderen Seite, machen die gleichen Dinge und spielen gut mit jeder Klasse, die von Ihnen erbt.

sich also fragen:

  • Erwartest du/Zulassungs-/Leute ermutigen Klassen zu schreiben, die von Ihrem Modul erben?
  • Definiert Ihr Modul eine komplexere Datenstruktur, die gut als Objekt funktioniert?

oder

  • Ist Ihr Modul eine Bibliothek von Dienstprogrammen, die auf grundlegenden Datentypen arbeiten?

Es gibt viel Platz in dieser Welt für beide, aber wenn Sie sich selbst finden, wie Sie in Bar haben, ignorieren $class (oder häufiger $self) im ganzen Modul, dann vielleicht haben Sie zu weit gegangen durch die Gestaltung sie als Methoden. Noch wichtiger ist, dass jeder, der versucht, von Ihrer marginal OO "Klasse" zu erben, eine grobe Überraschung bekommen wird, wenn Ihre Methoden den Unterschied zwischen den beiden Klassen nicht unterscheiden können ...

1

Dies ist mehr eine Frage des Code-Paradigmas.

Es ist absolut nichts falsch mit einem nicht objektorientierten Ansatz für Ihren Code. Es funktioniert, und es funktioniert gut.

Objektorientierung bietet jedoch eine Reihe von Vorteilen, die in Betracht gezogen werden sollten - und wenn sie etwas sind, das Sie wollen, gehen Sie eine OO-Route.

Speziell - Objekte bieten Verkapselung. Es macht es für mich viel einfacher, ein Modul zu schreiben und es einfach zu benutzen.Schauen Sie sich beispielsweise LWP::UserAgent für ein Beispiel:

require LWP::UserAgent; 

my $ua = LWP::UserAgent->new; 
$ua->timeout(10); 
$ua->env_proxy; 
$ua->agent('Mozilla/5.0'); 

my $response = $ua->get('http://search.cpan.org/'); 

if ($response->is_success) { 
    print $response->decoded_content; # or whatever 
} 
else { 
    die $response->status_line; 
} 

nun alle oben genannten Sie könnte über geerbt Subroutinen tun. Aber wenn Sie mehrere Abholungen von mehreren Seiten tun wollte, dann würden Sie müssen entweder:

  • ein Unter bauen, die alle Parameter haben Sie benötigt - einschließlich der Rückkehr irgendwie, ein Erfolg/Fehler/Ergebnis "- vielleicht in einem Array?
  • Sonst haben Sie "Zustand" in Ihrem externen Modul versteckt.

OO ist nur eine bessere, verständlichere Methode, dies zu tun. (Es gibt andere Vorteile von OO, die Sie sicher googlen könnten).

3

Der Entscheider ist, ob Ihr Module ein objektorientiertes Modul ist oder nicht.

  • Wenn Module ist einfach ein Behälter für eine Sammlung von Subroutinen, dann würde ich erwarten, dass es Exporter zu bedienen und bietet die Möglichkeit, eine Untergruppe von Subroutinen in den anrufenden Namensraum zu importieren. Ein Beispiel dafür ist List::Util

  • Auf der anderen Seite, wenn es ein Konstruktor Module::new, und die Absicht ist es in einer OO-Weise zu verwenden, dann sollten Sie nicht einfach Subroutinen mit Methoden mischen (außer vielleicht für privat Subroutinen dass das Modul intern verwendet). Ein Beispiel dafür ist LWP::UserAgent

So würde ich die Quellen wie die eine oder andere von ihnen geschrieben werden erwarten, und nicht eine Mischung dazwischen. Natürlich gibt es immer Situationen, in denen eine Faustregel ignoriert werden sollte, aber in diesem Fall kommt mir nichts in den Sinn.

Foo.pm

use strict; 
use warnings; 

package Foo; 

use Exporter 'import'; 
our @EXPORT_OK = qw/ subroutine /; 

sub subroutine { 
    my ($arg) = @_; 
    "Ordinary subroutine arg is $arg\n"; 
} 

1; 

Bar.pm

use strict; 
use warnings; 

package Bar; 

sub new { 
    my $class = shift; 
    bless {}, $class; 
} 

sub subroutine { 
    my $class = shift; 
    my ($arg) = @_; 
    "Class method arg is $arg\n"; 
} 

1; 

main.pl

#!/usr/local/bin/perl 

use strict; 
use warnings; 

use Foo 'subroutine'; 
use Bar; 

my $arg1 = "blah"; 

print subroutine($arg1); 
print Bar->subroutine($arg1); 

Ausgabe

Ordinary subroutine arg is blah 
Class method arg is blah