Die richtige Design ist eine Fabrik. Werfen Sie einen Blick darauf, wie die DBI
dies handhabt. Sie werden mit einer TransferAgent
Klasse enden, die eine beliebige Anzahl von TransferAgent::*
Klassen instanziiert. Offensichtlich wollen Sie mehr Fehler überprüfen, als die folgende Implementierung bietet. Wenn Sie eine Factory wie diese verwenden, können Sie neue Arten von Transferagenten hinzufügen, ohne Code hinzufügen oder ändern zu müssen.
TransferAgent.pm - die Factory-Klasse:
package TransferAgent;
use strict;
use warnings;
sub connect {
my ($class, %args) = @_;
require "$class/$args{type}.pm";
my $ta = "${class}::$args{type}"->new(%args);
return $ta->connect;
}
1;
TransferAgent/Base.pm
- enthält die Basisfunktionalität eines TransferAgent::*
Klasse:
package TransferAgent::Base;
use strict;
use warnings;
use Carp;
sub new {
my ($class, %self) = @_;
$self{_files_transferred} = [];
$self{_bytes_transferred} = 0;
return bless \%self, $class;
}
sub files_sent {
return wantarray ? @{$_[0]->{_files_sent}} :
scalar @{$_[0]->{_files_sent}};
}
sub files_received {
return wantarray ? @{$_[0]->{_files_recv}} :
scalar @{$_[0]->{_files_recv}};
}
sub cwd { return $_[0]->{_cwd} }
sub status { return $_[0]->{_connected} }
sub _subname {
return +(split "::", (caller 1)[3])[-1];
}
sub connect { croak _subname, " is not implemented by ", ref $_[0] }
sub disconnect { croak _subname, " is not implemented by ", ref $_[0] }
sub chdir { croak _subname, " is not implemented by ", ref $_[0] }
sub mode { croak _subname, " is not implemented by ", ref $_[0] }
sub put { croak _subname, " is not implemented by ", ref $_[0] }
sub get { croak _subname, " is not implemented by ", ref $_[0] }
sub list { croak _subname, " is not implemented by ", ref $_[0] }
1;
TransferAgent/FTP.pm
- implementiert eine (mock) FTP-Client:
package TransferAgent::FTP;
use strict;
use warnings;
use Carp;
use base "TransferAgent::Base";
our %modes = map { $_ => 1 } qw/ascii binary ebcdic/;
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->{_mode} = "ascii";
return $self;
}
sub connect {
my $self = shift;
#pretend to connect
$self->{_connected} = 1;
return $self;
}
sub disconnect {
my $self = shift;
#pretend to disconnect
$self->{_connected} = 0;
return $self;
}
sub chdir {
my $self = shift;
#pretend to chdir
$self->{_cwd} = shift;
return $self;
}
sub mode {
my ($self, $mode) = @_;
if (defined $mode) {
croak "'$mode' is not a valid mode"
unless exists $modes{$mode};
#pretend to change mode
$self->{_mode} = $mode;
return $self;
}
#return current mode
return $self->{_mode};
}
sub put {
my ($self, $file) = @_;
#pretend to put file
push @{$self->{_files_sent}}, $file;
return $self;
}
sub get {
my ($self, $file) = @_;
#pretend to get file
push @{$self->{_files_recv}}, $file;
return $self;
}
sub list {
my $self = shift;
#pretend to list remote files
return qw/foo bar baz quux/;
}
1;
script.pl
- wie man TransferAgent benutzt:
#!/usr/bin/perl
use strict;
use warnings;
use TransferAgent;
my $ta = TransferAgent->connect(
type => "FTP",
host => "foo",
user => "bar",
password => "baz",
);
print "files to get: ", join(", ", $ta->list), "\n";
for my $file ($ta->list) {
$ta->get($file);
}
print "files gotten: ", join(", ", $ta->files_received), "\n";
$ta->disconnect;
Ich würde empfehlen, ein bisschen mehr Beschreibung von dem, was hier vor sich geht, nur für den Fall, aber immer noch gute Antwort. –
Keine Notwendigkeit für definiert, da keiner der falschen Werte eine gültige Coderef ist. Außerdem sollten Sie eine Warnung ausgeben, wenn die Methode nicht in der Nachschlagetabelle gefunden werden kann. Eine Alternative besteht darin, alle Methoden in eine Klasse zu stellen und 'can' zu verwenden. –
@Sinan Ünür- Was ist, wenn $ trans_type eq "fronobulax?" Mit anderen Worten, ein Typ, den er nicht erwartet hatte oder nicht erwartet hatte? – xcramps