8

我正在使用 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 的直接调用成功。有没有办法保证这一点?

4

4 回答 4

10
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;
于 2009-11-14T18:44:33.760 回答
6

有点。您不能隐藏安装到符号表中的子例程,但可以使用词法变量来保存对匿名子例程的引用:

package SOD::MyOOInterface;

my $some_method = sub { ... }

$some_method->();

因为$some_method只在实现类的文件中可见,所以子程序不能被外部调用。缺点是不能作为方法调用,必须作为函数调用。如果要将其用作方法,则必须显式传递对象引用:

$some_method->($obj, @args);
于 2009-11-14T14:45:16.880 回答
6

不要将 PBP 用于对象练习。它很旧。事实上,现在关于 Perl 和对象的最佳实践可以在Moose中找到,它几乎是 Perl 的必备工具。

简而言之,Perl 模糊命名空间和类的方式大多数方法都可以在类上静态调用。这不是一件坏事,只是不要记录它。确实没有理由要将方法密封到实例中。没有私有方法有点烦人,但不依赖未记录方法的惯例是如此强大,以至于我们的社区已经足够了。

特征实际上是一个角色(不允许实例化),可以在运行时编译成一个对象。这将进一步掩盖您的典型用户的方法的起源(因为它们不会在原始类中),但它会产生运行时成本。有关特征的更多信息,请参阅MooseX::Traits

前面的下划线是一个很好的约定,进一步说明该方法对凝视的眼睛是私有的。

最后一点,如果您真的想提出这个问题,您可以使用 Class::MOP::Class->create_anon_class() 使用这些方法创建一个匿名类

于 2009-11-14T17:36:02.183 回答
1

我处理这个问题的方法是在方法的开头添加这样的东西:

my $self = shift;
croak "Instance method called on class" unless ref $self;

这绝不是真正的封装,但这确实意味着通过包调用您的人必须将对象实例作为第一个参数传递。一般来说,对于 Perl,我发现保护我的 API 的恶意用户没有多大意义——这只是帮助我捕捉到我不小心尝试将方法作为类方法调用的情况(这种情况比我想的更频繁)承认)。

就个人而言,我认为下划线约定 + 清楚地将方法记录为私有(或根本不记录它,因此它不会出现在 POD 中)足以满足实际使用。这也是它在 Python 中的工作方式。这是不限制用户的语言哲学的一部分。

Perl 模块宁愿你呆在它的客厅之外,因为你没有被邀请,而不是因为它有猎枪......

于 2009-11-14T15:08:17.673 回答