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

オブジェクトの練習にPBPを使用しないでください。とても古いです。実際、Perlとオブジェクトに関するベストプラクティスは、Perlにとってほぼ必須のMooseにあります。

要するに、Perlが名前空間とクラスをぼかす方法は、ほとんどのメソッドをクラスで静的に呼び出すことができます。これは悪いことではありません。文書化しないでください。メソッドをインスタンスに封印する理由は実際にはありません。プライベートメソッドがないのはちょっと面倒ですが、文書化されていないメソッドに依存しないという慣習は非常に強力であり、私たちのコミュニティには十分です。

トレイトは事実上、実行時にオブジェクトにコンパイルできる(インスタンス化を許可しない)役割です。これにより、通常のユーザーからのメソッドの起源がさらにわかりにくくなります(元のクラスに含まれないため)が、実行時間のコストがかかります。トレイトの詳細については、 MooseX::Traitsを参照してください。

アンダースコアを前に付けることは、メソッドがピアリングの目に対してプライベートであることをさらに述べるための優れた規則です。

最後の注意として、この問題を本当にプッシュしたい場合は、Class :: MOP :: Class-> create_anon_class()を使用して、これらのメソッドで匿名クラスを作成できる可能性があります。

于 2009-11-14T17:36:02.183 に答える
6

並べ替え。シンボル テーブルにインストールされているサブルーチンを非表示にすることはできませんが、レキシカル変数を使用して無名サブルーチンへの参照を保持できます。

package SOD::MyOOInterface;

my $some_method = sub { ... }

$some_method->();

はクラスを実装するファイルでのみ表示されるため$some_method、サブルーチンを外部から呼び出すことはできません。欠点は、メソッドとして呼び出すことができず、関数として呼び出す必要があることです。メソッドとして使用する場合は、オブジェクト参照を明示的に渡す必要があります。

$some_method->($obj, @args);
于 2009-11-14T14:45:16.880 に答える
1

これに対処する方法は、メソッドの先頭に次のようなものを追加することです。

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

これは決して真のカプセル化ではありませんが、パッケージを介して呼び出す誰かがオブジェクト インスタンスを最初の引数として渡す必要があることを意味します。一般に、Perl では、自分の API を悪意のあるユーザーから保護することにはあまり意味がないことがわかりました。これは、誤ってメソッドをクラス メソッドとして呼び出そうとする状況を検出するのに役立ちます (これは、私が望んでいるよりも頻繁に発生します)。認める)。

個人的には、アンダースコアの規則 + メソッドを非公開として明確に文書化する (または、POD に表示されないようにまったく文書化しない) ことで、実際の使用には十分だと思います。これは、Python での動作方法でもあります。これは、ユーザーを制限しないという言語哲学の一部です。

Perl モジュールは、ショットガンを持っているからではなく、招待されていないので、リビング ルームから離れることを好みます...

于 2009-11-14T15:08:17.673 に答える