这里正确的设计是工厂。看看这些DBI
处理方法。您将得到一个TransferAgent
实例化任意数量的类之一的TransferAgent::*
类。显然,您将需要比下面提供的实现更多的错误检查。使用这样的工厂意味着您可以添加新类型的传输代理,而无需添加或修改任何代码。
TransferAgent.pm - 工厂类:
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
- 包含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
- 实现(模拟)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
- 如何使用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;