在脚本中,我初始化几个处理程序并设置应该可用于单独模块中的函数的变量.这是使用它们(的最好方式$q,$dbh,%conf模块)?
伪模块示例:
package My::Module
sub SomeFunction (
@data = $dbh->selectrow_array("SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar} );
return $q->p( "@data" );
)
1;
Run Code Online (Sandbox Code Playgroud)
伪脚本示例:
use CGI;
use DBI;
use My::Module;
our $q = new CGI;
our $dbh = some_connenction_function($dsn);
our %conf = ( Foo => 1, Bar => 2, Random => some_dynamic_data() );
Run Code Online (Sandbox Code Playgroud)
我明白使用main::命名空间会起作用,但是sholud是更清洁的方式吗?或不?
package My :: Module您的模块应独立于上下文.也就是说,他们不应该期望那$dbh是数据库处理程序,或者他们应该返回内容$q.或者保留配置%conf.
例如,如果您突然发现自己有两个数据库句柄实例,该怎么办?你是做什么?当模块要求我使用模块特定变量进行配置时,我讨厌它,因为这意味着我不能使用该模块的两个不同实例.
所以你有两个选择:
让我们看一下使用伪代码的第一个实例:
sub someFunction (
%param = @_;
%conf = %{param{conf};
@data = $param{dbh}->selectrow_array(
"SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar}
);
return $param{q}->p( "@data" );
)
1;
Run Code Online (Sandbox Code Playgroud)
伪脚本示例:
use CGI;
use DBI;
use My::Module;
my $q = new CGI;
my $dbh = some_connenction_function($dsn);
my %conf = ( Foo => 1, Bar => 2, Random => some_dynamic_data() );
someFunction (
q => $q,
dbh => $dbh,
conf => \%conf,
);
Run Code Online (Sandbox Code Playgroud)
我在这里使用参数调用.还不错.是吗?现在,如果您需要另一个select语句,则可以使用不同的变量.
当然,但如果你不想一直传递变量怎么办呢.那么,您可以使用面向对象的技术.现在,放松,冷静下来.使用面向对象设计有很多很好的理由:
my $foo = Foo::Bar->new;类型的陈述.较新的Perl模块只有面向对象的接口,您将无法使用它们.让我们看看面向对象的方法是如何工作的.首先,让我们看看主程序:
use CGI;
use DBI;
use My::Module;
my $q = new CGI;
my $dbh = some_connenction_function($dsn);
my %conf = ( Foo => 1, Bar => 2, Random => some_dynamic_data() );
my $mod_handle = My::Module->new (
q => $q,
dbh => $dbh,
conf => \%conf,
);
$mod_handle->someFunction;
Run Code Online (Sandbox Code Playgroud)
在上面,我现在创建一个object instance包含这些变量.而且,奇迹般地,我已将您的功能更改为方法.方法只是类(aka模块)中的一个函数.诀窍在于我的实例(变量$mod_handler将所有必需的变量存储得很漂亮而且整洁.$mod_hander->语法只是将这些信息传递给我的函数我的意思是方法.
那么,你的模块现在是什么样的?让我们看看我有构造函数的第一部分,它只是为我需要的变量创建存储的函数:
sub new {
my $class = shift;
my %param = @_;
my $self = {};
bless $self, $class
$self->{Q} = $q;
$self->{DBH} = $dbh;
$self->{CONF} = $conf;
return $self;
}
Run Code Online (Sandbox Code Playgroud)
让我们看一下有点不同的第一件事:my $class = shift;.这是从哪里来的?当我用语法调用函数时Foo->Bar,我Foo作为函数中的第一个参数传递Bar.因此,$class等于My::Module.就像我用这种方式调用你的函数一样:
my $mod_handle = My::Module::new("My::Module", %params);
Run Code Online (Sandbox Code Playgroud)
代替:
my $mod_handle = My::Module->new(%params);
Run Code Online (Sandbox Code Playgroud)
接下来就是这my $self = {};条线.这是创建对哈希的引用.如果您不理解参考文献,您应该查看Perldocs中包含的Mark的参考教程.基本上,引用是存储数据的存储位置.在这种情况下,我的哈希没有名称,我所拥有的只是对存储它的内存的引用$self.在Perl中,没有什么特别的名称new或者$self,但它们是每个人都非常遵循的标准.
该bless命令正在引用我的引用$self,并将其声明为类型My::Module.这样,Perl可以跟踪是否$mod_handle是可以访问这些功能的实例类型.
如您所见,$self引用包含我的函数所需的所有变量.而且,我方便地将其传回我的主程序,我将其存储在其中$mod_handle.
现在,让我们来看看我的方法:
sub SomeFunction {
$self = shift;
my $dbh = $self->{DBH};
my $q = $self->{Q};
my %conf = %{self->{CONF}};
@data = $dbh->selectrow_array(
"SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar}
);
return $param{q}->p( "@data" );
}
Run Code Online (Sandbox Code Playgroud)
再一次,那条$self = shift;线.记住我称之为:
$mod_handle->SomeFunction;
Run Code Online (Sandbox Code Playgroud)
这与调用它是一样的:
My::Module::SomeFunction($mod_handle);
Run Code Online (Sandbox Code Playgroud)
因此,值$self是我存储的哈希引用$mod_handle.并且,该哈希引用包含我总是传递给此函数的三个值.
您永远不应在主程序和模块之间共享变量.否则,您不仅会在程序中每次都使用相同的名称,而且必须小心不要在程序的其他部分并行使用模块.
通过使用面向对象的代码,您可以在单个实例中存储所需的变量,并在同一实例中的函数之间来回传递它们.现在,您可以随意调用程序中的变量,并且可以在并行实例中使用模块.它可以改善您的计划和编程技巧.
除此之外,您还可以使用面向对象编程,因为它不会消失.它运作得很好.整个语言都是专门面向对象的,如果你不了解它是如何工作的,你永远不会提高你的技能.
而且,我提到小鸡挖了吗?
在所有Perl黑客降临到我之前.我想提一下我的Perl面向对象设计非常糟糕.它比你想要的更好,但是它有一个严重的缺陷:我已经将我的对象的设计暴露给了我班上的所有方法.这意味着如果我改变我存储数据的方式,我将不得不通过我的整个模块来搜索和替换它.
我这样做是为了保持简单,让我更清楚我在做什么.但是,任何面向好的面向对象的程序员都会告诉你(和我这样的二流黑客)是你应该使用setter/getter函数来设置你的成员值.
setter函数非常简单.模板看起来像这样:
sub My_Method {
my $self = shift;
my $value = shift;
# Something here to verify $value is valid
if (defined $value) {
$self->{VALUE} = $value;
}
return $self->{VALUE};
}
Run Code Online (Sandbox Code Playgroud)
如果我打电话给$instance->My_Method("This is my value");我的程序,它将设置$self->{VALUE}为This is my value.同时,它返回值$self->{VALUE}.
现在,让我说这就是这样:
my $value = $instance->My_Method;
Run Code Online (Sandbox Code Playgroud)
我的参数$value是未定义的,所以我没有设置值$self->{VALUE}.但是,我仍然会返回该值.
因此,我可以使用相同的方法来设置和获取我的价值.
让我们看看我的构造函数(这是该new函数的一个奇特名称):
sub new {
my $class = shift;
my %param = @_;
my $self = {};
bless $self, $class
$self->{Q} = $q;
$self->{DBH} = $dbh;
$self->{CONF} = $conf;
return $self;
}
Run Code Online (Sandbox Code Playgroud)
$self->{}好的设计说我应该使用这样的getter/setter函数,而不是直接在这个程序中设置哈希引用:
sub new {
my $class = shift;
my %param = @_;
my $self = {};
bless $self, $class
$self->Q = $q; #This line changed
$self->Dbh = $dbh; #This line changed
$self->Conf = $conf; #This line changed
return $self;
}
Run Code Online (Sandbox Code Playgroud)
现在,我不得不定义这三个子程序Q,Dbh和Conf,但现在我的SomeFunction方法去从这个:
sub SomeFunction {
$self = shift;
my $dbh = $self->{DBH};
my $q = $self->{Q};
my %conf = %{self->{CONF}};
@data = $dbh->selectrow_array(
"SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar}
);
return $param{q}->p( "@data" );
}
Run Code Online (Sandbox Code Playgroud)
对此:
sub SomeFunction {
$self = shift;
my $dbh = $self->Dbh; #This line changed
my $q = $self->Q; #This line changed
my %conf = %{self->Conf}; #This line changed
@data = $dbh->selectrow_array(
"SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar}
);
return $param{q}->p( "@data" );
}
Run Code Online (Sandbox Code Playgroud)
这些变化是微妙的,但很重要.现在我的new功能和我SomeFunction不知道这些参数是如何存储的.知道它们如何存储的唯一地方是getter/setter函数本身.如果我改变了类数据结构,除了getter/setter函数本身之外我不需要修改任何东西.
这是值得深思的......
如果你的所有SQL调用都在你的My :: Module函数中,那么为什么不简单地初始化它$dbh,然后在$q那里初始化.这样,您就不需要Use Dbi;在程序本身中包含该模块.实际上,您的程序现在仍然无法确切地知道数据的存储方式.你不知道它是一个SQL数据库,一个Mongo数据库,甚至是一些扁平的Berkeley风格的数据库结构.
我在很久以前的工作中包含了一个模块,我试图简化我们使用数据库的方式.这个模块做了几件事:
看看吧.它不是最好的,但你会看到我如何使用面向对象的设计来消除你遇到的所有问题.要查看文档,只需在perldoc MFX:Cmdata命令行中输入.
| 归档时间: |
|
| 查看次数: |
2646 次 |
| 最近记录: |