我正在使用Damian Conway的“由内而外”的对象,如他所描述的那本精彩的书Perl Best Practices,用于构建面向客户端安全系统的面向对象的接口。我想在我的模块中使用内部帮助器方法,我通常将其指定为“_some_method”。但是,这似乎打破了封装,因为它们可以通过包名直接调用。有没有办法让这些方法真正私密?例如,
use SOD::MyOOInterface;
my $instance1 = SOD::MyOOInterface->new();
$instance1->_some_method; #this produces an error:
SOD::MyOOInterface::_some_method; # this results in a
# successful method call
显然我不希望_some_method的直接调用成功。有什么方法可以保证这个吗?
答案 0 :(得分:11)
package Foo;
## declare inside-out hashes here:
my %attr_a;
my %attr_b;
## declare private methods here
my $private_1 = sub {
my $self = shift;
# can use $attr_a{$self} here...
...
};
my $private_2 = sub {
my $self = shift;
...
};
## public methods here
sub new { ... }
sub public_1 {
my $self = shift;
# can access attributes here
# can call private methods too, with slightly odd syntax:
my $result = $self->$private_1(@args);
...
}
1;
答案 1 :(得分:6)
排序。您无法隐藏已安装到符号表中的子例程,但您可以使用词法变量来保存对匿名子例程的引用:
package SOD::MyOOInterface;
my $some_method = sub { ... }
$some_method->();
因为$some_method
仅在实现类的文件中可见,所以子例程不能在外部调用。缺点是它不能作为方法调用,必须作为函数调用。如果要将其用作方法,则必须明确传递对象引用:
$some_method->($obj, @args);
答案 2 :(得分:6)
不要将PBP用于对象实践。这是非常古老的。事实上,现在关于Perl和对象的最佳实践可以在Moose中找到,这对于Perl几乎是必须的。
简而言之,Perl模糊命名空间和类的方式可以在类上静态调用大多数方法。这不是坏事,只是不记录它。没有理由想要将方法密封到实例中。没有私有方法有点烦人,但不依赖于无证方法的惯例是如此强大,它已经足够我们的社区。 p>
特征实际上是一个可以在运行时编译成对象的角色(不允许实例化)。这将进一步模糊典型用户的方法来源(因为它们不会在原始类中),但它会以运行时成本出现。 有关特征的更多信息,请参阅MooseX::Traits。
前置下划线是一个很好的惯例,可以进一步说明该方法对于窥视眼睛是私密的。
作为最后一点,如果你真的想推动这个问题,你可以使用Class :: MOP :: Class-> create_anon_class()
创建一个带有这些方法的匿名类。答案 3 :(得分:1)
我处理这个的方法是在方法的开头添加这样的东西:
my $self = shift;
croak "Instance method called on class" unless ref $self;
它绝不是真正的封装,但它确实意味着有人通过包调用你将不得不传递一个对象实例作为第一个参数。通常使用Perl,我发现保护我的API的恶意用户没有太大意义 - 这只是帮助我抓住我不小心尝试将该方法作为类方法调用的情况(这种情况比我想要的更频繁)承认)。
就我个人而言,我认为下划线约定+明确地将该方法记录为私有(或者根本不记录它,因此它没有显示在POD中)足以实际使用。这也是它在Python中的工作原理。它是language philosophy不限制用户的一部分。
Perl模块更喜欢你没有被邀请而离开它的起居室,而不是因为它有霰弹枪......