为什么不在创建新的Perl模块时直接使用__PACKAGE__呢?

pu82cl6c  于 2022-11-15  发布在  Perl
关注(0)|答案(2)|浏览(129)

我希望我知道有什么参考资料或文档告诉我这是在Perl中创建新对象的最佳方法:

sub new {
   my $package = shift;
   my $class = ref($package) || $package

这是我多年来创建对象的方法,但现在我想知道为什么要这么麻烦?除了一些边缘情况,为什么不简单地做以下几点:

sub new {
    shift; # get rid of the object or package name
    my $class = __PACKAGE__;

如果没有特殊的原因来检测调用“new”方法的命名空间,那么简单地使用__PACKAGE__会有什么问题吗?

sqxo8psd

sqxo8psd1#

继承

# classA.pm 
package ClassA;
sub new { $pkg = ref($_[0]) || $_[0] ; bless { foo => 42 }, $pkg }

# classB.pm
package ClassB;
use parent 'ClassA';
sub foo { ... }

# main.pl
use ClassA;
use ClassB;
$B = ClassB->new();
print $B->foo();

在这个例子中,ClassB继承了ClassA的方法,包括它的构造函数,但是我们仍然希望将对象标识为属于ClassB,所以ClassA中的构造函数必须尊重传递给它的构造函数的引用的名称。
更简单、更安全

$B = bless { ClassA->new(), "ClassB" };   # or
$B = bless { ClassB->new(), "ClassA" };

或者在ClassB中添加传递构造函数。

package ClassB;
use parent 'ClassA';
sub new { bless { ClassA::new(@_), __PACAKGE__ } }
fbcarpbf

fbcarpbf2#

类名已经是构造函数的第一个参数了,为什么不使用它呢?你不需要去接触任何东西,如果你认为情况比你最初想象的要复杂,你也没有人为地造成一个减速带。下面的代码可以使用继承,也可以不使用继承:

sub new { 
    my( $class, @args ) = @_;
    ...
    bless {...}, $class;
    }

考虑一下你所编写的任何程序,如果代码情况发生变化,你需要做多少修改。也许你添加了一些你并不立即需要的额外步骤,但是当你意识到你确实需要这些情况时,这可以保持代码的灵活性。在你的例子中,您实际上必须做额外的工作来忽略Perl专门提供的invocant参数,该参数告诉您哪个类正在尝试创建新对象。
例如,你创建了你的类,它为你工作,并且很好地完成了它的工作。它工作得如此之好,以至于你可以共享它,其他人也可以使用它,他们对它很满意一段时间,直到他们需要这个小小的修改。他们应该能够子类化你的模块(因此,对它或对您来说没有任何更改)来扩展或重写方法。但是,您的代码不允许这样做,因为您使用了一种限制性更强的方式来祝福对象,而这种方式并没有带来任何好处。
你的问题中的第一段代码也使用了第一个参数,但它并不是构造函数的处方。它允许一个已经存在的对象创建一个新的对象,这是一件额外的事情。ref从对象中提取包名,并将其用于新对象。
我不是特别喜欢这种创建新对象的方式,而且我认为它的界面可能会让人感到困惑。当你在一个已有对象上调用new时,会发生什么?你会克隆已有对象吗?如果是,还有更好的名字,比如clone(Ruby使用dup)。你得到了一个完全新鲜的对象吗?如果是的话,为什么要遍历一个现有的对象来得到一个与它完全无关的对象呢?
曾经有一段时间,很多OO Perl的例子都展示了同样的构造函数,它被复制并粘贴到了很多地方。但从那以后,我们学到了很多。也许你有一个很好的答案,为什么你会允许这样做,但到目前为止,我还没有听到一个令人信服的答案。

相关问题