Perlでは、継承は配列@ISAを使用して実装されており、これは現在のパッケージがどのパッケージ(クラス)から継承されているかを示します。これは多くの他の言語での伝統的なオブジェクト指向ではなく、むしろメソッドを探す際に親を動的に置き換えるものです。
初期のPerlバージョンでは、標準のオブジェクト指向アプローチは存在しませんでした。継承をサポートするために、親クラスが列挙される配列@ISA(ISA = Is A)が導入されました。Perlは、最初にオブジェクトのクラス内でメソッドを探し、その後親の順に探すため、特定の柔軟性を持ちますが、その一方で独自の特徴も生じます。
@ISAを介した継承方法は、カプセル化を簡単に破壊します。さらに、多重(複数)継承は、親の順序に慎重に対処しないと予期しないメソッドの競合を引き起こす可能性があります。重要なのは、メソッドの探索順序(Method Resolution Order)であり、特にCPANモジュール(例えば、Moose、base、またはparentからのクラス)を使用する場合には明らかでないことがあります。
Perlでの簡単な継承には、配列@ISAの宣言を使用します:
package Parent; sub hello { print "Hello from parent! "; } package Child; our @ISA = ('Parent'); Child::hello(); # 出力: Hello from parent!
実際のプロジェクトでは、継承の作業を簡素化し、安全性を高めるために、プラグマbaseやparentを使用することがよくあります。
@ISAを通じて管理されます。BASEプラグマや@ISA配列の使用により、プログラムの実行後に親のメソッドを子クラスに追加できますか?
いいえ、Perlはスクリプトのコンパイル時に継承を許可し、実行時には許可しません。@ISAの変更が実行時に発生する場合、実際には既に宣言されたすべてのオブジェクトには影響しないため、奇妙な問題を引き起こす可能性があります。
package Parent; sub hello { print "parent "; } package Child; our @ISA = ('Parent'); # オブジェクトが作成された後に@ISAを変更することは推奨されません
@ISA内の複数の親クラスで同じメソッドを宣言するとどうなりますか?
最初に@ISAで指定された順序で見つかったものが呼び出されます。これは特に多重継承の場合、予期しない動作を引き起こす可能性があります。
package Base1; sub hello { print "Base1 "; } package Base2; sub hello { print "Base2 "; } package Derived; our @ISA = ('Base1', 'Base2'); Derived::hello(); # 出力: Base1
@ISAにクラスを動的に追加し、そのメソッドにアクセスすることはできますか?
はい、可能ですが、これは極めて推奨されません。プログラムの構造を壊し、メソッド解決のエラーや実行時エラーを引き起こす可能性があります。
@ISAを変更するparent/baseを使用しないことで、保守性が低下するプロジェクトでは、プロトコルクラスに機能を追加するために、条件に応じて動的にインポートされたモジュールからメソッドを継承するために、手動で@ISA配列を変更します。
利点:
欠点:
クラスを拡張するためにプラグマparentを使用し、親の順序を厳密に制御し、オーバーライド可能なメソッドを明示的に定義します。
利点:
欠点: