El diseño correcto aquí es una fábrica Eche un vistazo a cómo lo maneja el DBI
. Concluirá con una clase TransferAgent
que ejemplifica una de una serie de TransferAgent::*
clases. Obviamente, deseará más comprobación de errores de la que proporciona la implementación a continuación. Usar una fábrica como esta significa que puede agregar nuevos tipos de agentes de transferencia sin tener que agregar o modificar ningún código.
TransferAgent.pm - la clase de fábrica:
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
- contiene la funcionalidad básica de una clase TransferAgent::*
:
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
- implementa un cliente (simulacro) FTP:
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
- cómo utilizar TransferAgent:
#!/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;
Recomendaría añadir un poco más de descripción de lo que está sucediendo aquí por las dudas, pero sigue siendo una buena respuesta. –
No es necesario definirlo porque ninguno de los valores falsos es un valor de referencia válido. Además, debe emitir una advertencia si el método no se puede encontrar en la tabla de búsqueda. Una alternativa es poner todos los métodos en una clase y usar 'can'. –
@Sinan Ünür- ¿Qué pasa si $ trans_type eq "fronobulax?" En otras palabras, ¿un tipo que no esperaba o no había anticipado? – xcramps