简而言之,我尝试使用网络中每个实例的对象对网络拓扑进行建模。另外,我得到了一个高级经理类,负责管理这些对象和执行完整性检查。文件结构看起来像这样(我省略了大多数目标文件,因为它们的结构都相当相等):
Manager.pm
Constants.pm
Classes/
+- Machine.pm
+- Node.pm
+- Object.pm
+- Switch.pm
我来自OOP已有好几年了,我喜欢代码重用等。因此,我在thos对象之间设置了继承,继承树(在此示例中)如下所示:
Switch -+-> Node -+-> Object
Machine -+
所有这些对象的结构如下:
package Switch;
use parent qw(Node);
sub buildFromXML {
...
}
sub new {
...
}
# additonal methods
现在有趣的部分:
问题1
如何在不静态输入名称的情况下确保正确加载所有这些对象?
潜在的问题是:如果我只是
require "$_" foreach glob("./Classes/*");
,则会收到许多“新的子例程重新定义于”错误。我还尝试了use parent qw(-norequire Object)
,Module::Find
和其他一些@INC
修改的各种组合,简而言之:它没有用。目前,我正在静态导入所有使用的类,它们会自动导入其父类。所以,基本上,我要问的是:(perl-)正确的做法是什么?
和高级:能够创建更复杂的文件夹结构(因为将有很多对象)并且仍然具有继承+“自动加载”功能,将非常有帮助
问题2-解决了
如何“分享我的进口”?我使用了几个库(我自己的库,其中包含一些辅助函数,
LibXML
,Scalar::Util
等),我想在我的对象之间共享它们。 (其背后的原因是,我可能需要向所有对象添加另一个通用库,并且很有可能会超过100个对象-手动编辑所有对象并使用正则表达式/脚本进行理论上的工作很有趣,但理论上是可行的,但是似乎不是最干净的解决方案)我试过的
Manager.pm
中的所有内容->在Manager程序包中工作-给我类似“未定义的子例程&Switch::trace称为”的错误include.pl
文件并将do
/require
/use
文件-给我相同的错误。 include.pl
基本上看起来像这样:use lib_perl;
use Scalar::Util qw(blessed);
use XML::LibXML;
use Data::Dumper;
use Error::TryCatch;
...
我再次问:正确的方法是什么?我是在使用正确的方法而只是执行失败,还是应该完全更改我的结构?
没关系,为什么我当前的代码不能很好地工作,到目前为止,为这些问题提供正确,干净的方法就足够了:)
编辑:完全忘记了perl版本-_-旁注:我无法升级perl,因为我需要使用5.8卡住的库:/
C:\> perl -version
This is perl, v5.8.8 built for MSWin32-x86-multi-thread
(with 50 registered patches, see perl -V for more detail)
Copyright 1987-2006, Larry Wall
Binary build 820 [274739] provided by ActiveState http://www.ActiveState.com
Built Jan 23 2007 15:57:46
最佳答案
这只是对问题2(共享进口)的部分回答。
加载模块(通过use
)有两件事:
perldoc -f require
。 import
子项。这会将一些子或常量等加载到调用者的 namespace 中。这是Exporter
类在很大程度上隐藏起来的过程。这部分对于使用不带全名的潜艇等非常重要,例如max
而不是List::Util::max
。参见perldoc -f use
。 让我们查看以下三个模块:
A
,B
和User
。{
package A;
use List::Util qw(max);
# can use List::Util::max
# can use max
}
{
package User;
# can use List::Util::max -> it is already loaded
# cannot use max, this name is not defined in this namespace
}
软件包B
定义了一个子load
,该子eval
将预定义的模块和子列表加载到调用者 namespace 中:{
package B;
sub load {
my $package = (caller())[0]; # caller is a built-in, fetches package name
eval qq{package $package;} . <<'FINIS' ;
use List::Util qw(max);
# add further modules here to load
# you can place arbitrarily complex code in this eval string
# to execute it in all modules that call this sub.
# (e.g. testing and registering)
# However, this is orthogonal to OOP.
FINIS
if ($@) {
# Do error handling
}
}
}
在User
'd字符串中,我们暂时切换到调用程序包,然后加载指定的模块。这意味着load
包代码现在如下所示:{
package User;
B::load();
# can use List::Util::max
# can use max
}
但是,您必须确保use B
子本身已经加载。如果有疑问,请输入B::load()
。在模块的其余部分编译之前,最好在BEGIN
阶段执行eval
:{
package User;
BEGIN {use B; B::load()}
# ...
}
相当于{
package User;
use B;
use List::Util qw(max);
# ...
}
TIMTOWTDI。尽管我发现do
编码的代码非常凌乱和危险,但这是我在这种情况下追求的方式(而不是Import::Into
ing文件,该文件相似但有不同的副作用)。相比之下,手动混淆程序包 namespace 中的typeglobs真是令人头疼,复制粘贴模块名称列表就像回到甚至没有C的预处理器的时代。编辑:
B
…是一个CPAN模块,通过一个有趣的方法界面提供此功能。使用此模块,我们将通过以下方式重新定义
eval
包:{
package B;
use List::Util; # you have to 'use' or 'require' this first, before using 'load'.
use Import::Into; # has to be installed from CPAN first
sub load {
my $package = caller;
List::Util->import::into($package, qw(max));
# should work too: strict->import::into($package);
# ...
}
}
该模块从 View 中隐藏了所有脏活(ojit_code ing),并执行方法调用解析体操,以允许将编译指示导入其他 namespace 。关于perl - Perl:动态模块加载,对象继承和 “common helper files”,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12419357/