代码之家  ›  专栏  ›  技术社区  ›  ennuikiller

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

  •  8
  • ennuikiller  · 技术社区  · 15 年前

    我用的是达米安·康威的《由内而外》作品,正如他所描述的那本好书。 Perl Best Practices 在我的客户机上构造一个面向对象的安全系统接口。我遇到了在我的模块中使用内部助手方法的需求,我通常将其指定为“一些”方法。但是,这似乎破坏了封装,因为可以通过包名称直接调用它们。有没有办法让这些方法真正私有化?作为一个例子,

    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 
    

    显然,我不想直接调用某个方法来成功。有没有办法保证?

    4 回复  |  直到 15 年前
        1
  •  6
  •   Ether    15 年前

    不要将PBP用于对象实践。它很古老。实际上,关于Perl和对象的最佳实践可以在 Moose 几乎是Perl必须具备的功能。

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

    特性实际上是一个角色(不允许实例化),可以在运行时编译为对象。这将进一步模糊典型用户的方法来源(因为它们不在原始类中),但它是以运行时为代价的。 见 MooseX::Traits 有关特性的更多信息。

    预先准备好的下划线是进一步说明这种方法对窥视者来说是私有的一种很好的约定。

    最后一点要注意的是,如果您真的想推动这个问题,您可能可以使用class::mop::class->create_an_class()使用这些方法创建一个匿名类。

        2
  •  11
  •   Randal Schwartz    15 年前
    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;
    
        3
  •  6
  •   Michael Carman    15 年前

    某种程度上。不能隐藏已安装到符号表中的子例程,但可以使用词法变量保存对匿名子例程的引用:

    package SOD::MyOOInterface;
    
    my $some_method = sub { ... }
    
    $some_method->();
    

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

    $some_method->($obj, @args);
    
        4
  •  1
  •   ire_and_curses    15 年前

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

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

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

    就我个人而言,我认为强调约定+将方法清晰地记录为私有(或者根本不记录它,这样它就不会出现在pod中)就足以用于现实世界。这也是它在Python中的工作方式。它是 language philosophy 不限制用户。

    Perl模块希望您不要呆在它的起居室,因为您没有被邀请,而不是因为它有一把猎枪…