如何在面向对象的 Perl 中定义私有或内部方法?

发布于 2024-08-11 18:16:00 字数 587 浏览 5 评论 0原文

我正在使用 Damian Conway 的“由内而外”对象,正如他精彩的书所描述的那样 Perl 最佳实践 在我的客户端构建一个面向对象的安全系统接口。我遇到需要在我的模块中使用内部辅助方法,我通常将其指定为“_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 成功。有什么办法可以保证这一点吗?

I'm using Damian Conway's "inside-out" objects as described is his wonderful book Perl Best Practices to construct an object-oriented interface to a security system at my client. I'm coming across the need to use internal helper methods within my module that I would normally designate as "_some_method". However, this seems to break encapsulation since they can be called directly via the package name. Is there any way of making these methods truly private? As an example,

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 

Obviously I don't want the direct call of _some_method to succeed. Is there any way of guaranteeing this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

幽梦紫曦~ 2024-08-18 18:16:00
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;
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;
無處可尋 2024-08-18 18:16:00

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

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

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

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

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

Don't use the PBP for object practices. It is very old. In fact, now the best practices regarding Perl and objects can be found in Moose, an almost must-have for Perl.

In short, the way Perl blurs namespaces and classes most methods can be called statically on the class. This is not a bad thing, just don't document it. There is really no reason to want to seal the methods into the instance. Not having private methods is kind of annoying but the convention of not relying on undocumented methods is so strong it has sufficed for our community.

A trait is effectively a role (doesn't permit instantiation) that can be compiled into an object at runtime. This will further obscure the origin of the methods from your typical user (because they won't be in the original class), but it comes at a runtime cost.
See MooseX::Traits for more information on traits.

The prepending underscore is a great convention to further state the method is private to peering eyes.

As a last note if you really want to push this issue, you might be able to create an anonymous class with those methods using Class::MOP::Class->create_anon_class()

夜吻♂芭芘 2024-08-18 18:16:00

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

package SOD::MyOOInterface;

my $some_method = sub { ... }

$some_method->();

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

$some_method->($obj, @args);

Sort of. You can't hide a subroutine that's installed into the symbol table, but you can use a lexical variable to hold a reference to an anonymous subroutine:

package SOD::MyOOInterface;

my $some_method = sub { ... }

$some_method->();

Because $some_method is only visible in the file implementing the class, the subroutine can't be called externally. The drawback is that it can't be called as a method, it must be called as a function. If you want to use it as a method you'll have to pass the object reference explicitly:

$some_method->($obj, @args);
離人涙 2024-08-18 18:16:00

我处理这个问题的方法是在方法的开头添加类似的内容:

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

它绝不是真正的封装,但它确实意味着有人通过包调用您必须传递一个对象实例作为第一个参数。一般来说,对于 Perl,我发现防止恶意用户使用我的 API 没有太多意义 - 这只是帮助我捕获我不小心尝试将方法作为类方法调用的情况(这种情况发生的频率比我希望的要高)承认)。

就我个人而言,我认为下划线约定 + 明确将该方法记录为私有(或者根本不记录它,因此它不会出现在 POD 中)足以满足实际使用的需要。这也是 Python 中的工作原理。它是 不限制用户的语言哲学

Perl 模块希望你远离它的客厅,因为你没有被邀请,而不是因为它有一把猎枪......

The way I deal with this is to add something like this at the start of the method:

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

It's in no way true encapsulation, but it does mean someone calling you via the package will have to pass an object instance as the first argument. In general with Perl, I find there isn't much point in protecting against malicious users of my API - this just helps me catch situations where I accidentally try calling the method as a class method (which happens more often than I'd like to admit).

Personally, I think the underscore convention + clearly documenting the method as private (or not documenting it at all so it doesn't show up in the POD) is sufficient for real-world use. This is also how it works in Python. It's part of the language philosophy of not restricting users.

A Perl module would prefer that you stay out of its living room because you weren't invited, not because it has a shotgun...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文