我需要在Perl中编写一个与存储相关的应用程序.该应用程序需要将文件从本地计算机上载到其他一些存储节点.目前,上传方法是FTP,但将来它可能是bittorrent或一些未知的超文件传输方法.
对于需要上传的每个文件,都有一个配置文件,用于定义文件名,文件将上传到的存储节点以及上传过程中应使用的传输方法.
当然,我可以使用以下方法来解决我的问题:
{
if ( $trans_type == "ftp" ) { ###FTP the FILE}
if ( $trans_type == "bit" ) { ###BIT the FILE}
### etc ###
}
Run Code Online (Sandbox Code Playgroud)
但即使我在学校学到了基本的OO知识,我仍然觉得这不是一个好的设计.(问题标题可能有点误导.如果你认为我的问题可以通过非OO解决方案优雅地解决,那对我来说还是可以的.实际上它会更好,因为我的OO知识有限.)
那么你们一般可以给我一些建议吗?当然,如果你提供一些示例代码,这将是一个很大的帮助.
xcr*_*mps 13
首先,Perl中的字符串相等测试eq
不是==
.
如果你有方法来做这项工作,比如说bit和ftp,
my %proc = (
bit => \&bit,
ftp => \&ftp,
);
my $proc = $proc{$trans_type};
$proc->() if defined $proc;
Run Code Online (Sandbox Code Playgroud)
你可以使用哈希...
让每个传输方法在哈希中注册自己.您可以执行此OO(通过在某些传输方法工厂上调用方法)或在程序上(只需将哈希值设置为包变量,或者如果您不想模块化,甚至可以将其放在主包中).
package MyApp::Transfer::FTP;
$MyApp::TransferManager::METHODS{ftp} = \&do_ftp;
sub do_ftp { ... }
1;
Run Code Online (Sandbox Code Playgroud)每种传输方法都使用一致的API.也许它只是一个功能,或者它可能是一个对象接口.
通过哈希调用传输.
sub do_transfer {
# ...
my $sub = $MyApp::TransferManager::METHODS{$method}
or croak "Unknown transfer method $method";
$sub->($arg1, $arg2, ...);
# ...
}
Run Code Online (Sandbox Code Playgroud)顺便说一句:OO寄存器方法看起来像这样:
package MyApp::TransferManager;
use Carp;
use strict;
my %registered_method;
sub register {
my ($class, $method, $sub) = @_;
exists $registered_method{$method}
and croak "method $method already registered";
$registered_method{$method} = $sub;
}
# ...
1;
Run Code Online (Sandbox Code Playgroud)
(此代码均未经过测试;请原谅丢失的分号)
这里的正确设计是工厂.看看如何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;
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3029 次 |
最近记录: |