我正在构建一个脚本,需要一些关于重复代码的帮助。
这是我的构造函数:
sub new {
my $class = shift;
my $self = {
ip => shift,
username => shift,
password => shift,
need_enable => 0,
enable => '',
};
my $session = Net::Telnet->new( Timeout => 2, Errmode => 'return');
$self->{session} = $session;
bless($self, $class);
}
以下是一些方法:
sub _send_enable {
my $self = shift;
my $session = $self->{session};
...
sub _command {
my $self = shift;
my $session = $self->{session};
my $command = shift;
...
sub _match_prompt {
my $self = shift;
my $session = $self->{session};
my ( $prematchU , $matchU ) =
$session->waitfor(match => '/(?m:^[\w.-]+\s?(?:\(config[^\)]*\))?\s?[\$#>]\s?(?:\(enable\))?\s*$)/',
Timeout => 10);
return ($prematchU,$matchU);
}
正如您所看到的,在这些方法中,我需要回忆一下在构造函数中初始化的telnet实例。
我有更多方法,在这些方法中我需要再次回忆一下telnet实例。
此外,我需要在方法中调用一些方法。我总是需要将对象作为第一个参数:
_command($self, 'show privilege');
_check_enable($self);
可能我错过了我在“中级Perl”中学到的东西,我觉得我可以避免所有重复的代码。
感谢您的任何建议!
答案 0 :(得分:5)
首先要做的事情。这样:
_command($self, 'show privilege');
_check_enable($self);
非常错误。要在Perl中调用方法,您需要使用
$self->_command( 'show privilege' );
$self->_check_enable();
(在第二行中,您可以省略parens,因为参数列表为空。)
->
运算符告诉Perl您要调用方法而不是常规子例程。如果左侧的东西是受祝福的引用,则使用它的包被用于查找方法。否则,左侧的东西被假定为类名。在任何一种情况下,Perl都将左边的东西作为第一个项放入参数列表中。
使用->
和直接调用子例程之间的重要区别是->
语法使Perl查找可能在该类或父类中的方法。直接调用子程序不会通过方法调度程序。
至于访问对象本身,Perl中的标准约定是
my $self = shift;
但这不是必需的。由于您的方法的参数来自常规@_
arguments数组,因此您可以使用$_[0]
。您也可以使用$_[0]{session}
作为会话对象。但恕我直言,如果你将它解压缩到一个命名变量,它更整洁,更容易阅读。
如果您想避免所有重复输入以定义$self
,您可以使用类似Method::Signatures的内容,它会为您提供一个花哨的method
关键字来解包$self
你。
所以这个:
sub _command {
my $self = shift;
my $session = $self->{session};
my $command = shift;
...
成为这个:
method _command( $message ) {
# $self and $message are already defined, so just use them
...
答案 1 :(得分:3)
我的模块Moops旨在重复Perl OO。这是一个例子......
use Moops;
use Net::Telnet;
class My::Class :ro {
has ip => ();
has username => ();
has password => ();
has need_enable => (default => 0);
has enable => (default => '');
has session => (builder => 1);
method BUILDARGS ($ip, $username, $password) {
return {
ip => $ip,
username => $username,
password => $password,
};
}
method _build_session () {
Net::Telnet->new(Timeout => 2, Errmode => 'return');
}
method _send_enable () {
my $session = $self->session;
...;
}
method _command ($command) {
my $session = $self->session;
...;
}
method _match_prompt () {
$self->session->waitfor(
match => '/(?m:^[\w.-]+\s?(?:\(config[^\)]*\))?\s?[\$#>]\s?(?:\(enable\))?\s*$)/',
Timeout => 10,
);
}
}
答案 2 :(得分:2)
你可以消除my $self = shift;
。毕竟,那只是$_[0]
。您只需使用$_[0]->{session}
而不是经常my $session = $self->{session}
。这也将解决接受性的一些。
但是,重复性对于文档目的很有用。当我在my $self = shift;
定义下看到sub
时,我立即知道这是一个方法而不是构造函数或普通的子程序。
当我编写方法和构造函数时,我的前几行获取参数。我还从构造函数和方法中隐藏结构或我的对象。它确实意味着编写更多代码行,但该代码有助于记录我尝试做的事情。这是一个很好的方法来捕捉可能的错误,或帮助那些必须维护和调试我的代码的穷人。
例如,以下是我将如何构建构造函数:
sub new {
my $class = shift;
my $ip = shift;
my $username = shift;
my $password = shift;
my $self = {};
bless $self, $class;
$self->ip($ip);
$self->username($username);
$self->password($password);
$self->need_enable(0);
$self->enable('');
my $session = Net::Telnet->new( Timeout => 2, Errmode => 'return' );
$self->session($session);
return $self;
}
这是更多的写作,也许你称之为重复,但......
my $class = shift;
)。以下是我的session
方法的样子:
my session {
my $self = shift;
my $session = shift;
if ( defined $session ) {
if ( not $self->isa("Net::Telnet") ) {
croak qq(Session parameter must be a "Net::Telnet" object.);
}
$self->{session} = $session;
}
return $self->{session};
}
这是我的代码中唯一提到会话信息实际存储在我的对象中的地方。通过创建一个单独的方法来设置/获取我的会话,我可以做一些测试。例如,我想测试会话是否是Net::Telnet
对象。如果我决定更改会话存储在我的对象中的方式,这是我必须触摸的代码中唯一的位置。
当然,现在我想要消除更多重复:
sub _command {
my $self = shift;
my $command = shift;
my $session = $self->session;
...
根据我在这个答案开头给出的建议,你可以消除很多重复:
sub _command {
my $command = $_[1];
... $_[0]->{session} ... # Some line where you need session.
但是,你会得到什么?一些可怜的schlub维护你的代码有多容易?如果您改变存储会话的方式怎么办?例如,您决定使用inside out objects。想象一下,浏览代码并查找$[0]->{session}
之类的内容并进行修改。谈论无聊,容易出错的重复任务!
然而,并非完全失去了。而不是像这样不断重复getter / setter方法:
sub some_method {
my $self = shift;
my $some_method = shift;
if ( defined $some_method ) {
$self->{some_method} = $some_method;
}
return $some_method;
}
您可以使用Class::Struct模块。关于Class::Struct
的好处是它是一个标准的Perl模块。它已经安装好了。
使用Class::Struct
可以消除大多数getter / setter方法定义。相反,您需要做的就是编写一些代码实际上正在做有趣事情的方法。例如,我有一个程序有超过40个与之关联的方法,但使用Class::Struct
将其降低到不到10个。
另一个选项是Moose,它非常灵活,功能强大,可能就像Perl对象的使用方式一样。它隐藏了许多获取/设置内容和对象的结构。与驼鹿有很多争议。它大,慢,笨重。它也可能是复杂而复杂的。有很多像Mouse这样的软件包试图消除很多问题,同时只丢失一些更深奥的功能。
答案 3 :(得分:0)
非常感谢你的时间。
我现在使用箭头操作符( - >)更改了方法调用。
我在编写更多行时没有问题,但我想确定这些行是否必不可少或者我缺少一些OOP概念(Intermediate Perl教授有关修复重复代码的内容)。
我也要检查Moops模块。
要了解这个论坛是如何运作的。我刚刚添加了4个空格,但事情没有缩进我的预期。
非常感谢!