这里的正确设计是工厂模式。看一下
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;
$self->{_connected} = 1;
return $self;
}
sub disconnect {
my $self = shift;
$self->{_connected} = 0;
return $self;
}
sub chdir {
my $self = shift;
$self->{_cwd} = shift;
return $self;
}
sub mode {
my ($self, $mode) = @_;
if (defined $mode) {
croak "'$mode' is not a valid mode"
unless exists $modes{$mode};
$self->{_mode} = $mode;
return $self;
}
return $self->{_mode};
}
sub put {
my ($self, $file) = @_;
push @{$self->{_files_sent}}, $file;
return $self;
}
sub get {
my ($self, $file) = @_;
push @{$self->{_files_recv}}, $file;
return $self;
}
sub list {
my $self = shift;
return qw/foo bar baz quux/;
}
1;
script.pl
- 如何使用TransferAgent:
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;
if ($proc {$trans_type} {'process_file'})
将不存在的$proc {$trans_type}转换为一个空哈希的引用,但是仅仅查找哈希中的值并不会在那里创建哈希元素。 - ysth