諸君、日々のCOBOL開発、お疲れ様です。今回は、モダンCOBOL(2002以降)でオブジェクト指向プログラミングを実践する上で、避けては通れない非常に重要なキーワード、SELF(自己参照一意名)について解説していこう。
1. 導入: なぜSELFが重要なのか
オブジェクト指向COBOLでクラスを設計し、インスタンスを操作する際、一つのインスタンスが自身の持つデータや他のメソッドと連携することは日常茶飯事だ。例えば、「このインスタンスの値を更新した後、その結果を画面に表示する」といった処理はよくあるだろう。
このような場合、自身のインスタンスのメソッドを呼び出したり、自身を引数として他のオブジェクトに渡したりする必要が出てくる。ここで活躍するのがSELFだ。SELFを使うことで、
- コードの可読性が向上し、どのインスタンスのメソッドを呼んでいるのかが明確になる。
- 保守性が向上し、クラス内部の変更が呼び出し側に与える影響を最小限に抑えられる。
- オブジェクト指向の重要な原則であるカプセル化を促進し、より堅牢なシステム設計が可能になる。
SELFを理解することは、COBOLで本格的なオブジェクト指向開発を進める上での第一歩と言っても過言ではない。しっかり理解して、現場で役立ててくれ。
2. 基礎知識: SELFとは何か
SELFは、現在実行中のインスタンス(オブジェクト)自身を指し示すための特別な予約語だ。他のオブジェクト指向言語における`this`(Java, C++, C#など)や`self`(Python, Rubyなど)と全く同じ概念だと考えてもらって構わない。
- インスタンス: クラスという設計図を元に生成された、メモリ上に実体を持つオブジェクトのこと。
- メソッド: インスタンスが持つ機能や処理を定義したもの。
つまり、あるインスタンスのメソッドが実行されている最中に、そのメソッドが「自分自身」を指したい場合にSELFを用いるわけだ。これは、そのインスタンスが持つデータ(インスタンス変数)にアクセスしたり、そのインスタンスが持つ別のメソッドを呼び出したりする際に非常に強力なツールとなる。
3. 実装/解決策: SELFの具体的な使い方
SELFの最も一般的な使い方は、自身のインスタンスメソッドを呼び出す場合と、自身を引数として他のメソッドに渡す場合の2つだ。
自身のインスタンスメソッドを呼び出す
クラス内部で、そのクラスの別のメソッドを呼び出したい場合に利用する。
INVOKE SELF "メソッド名"
この記述により、現在実行中のインスタンス自身が持つ指定されたメソッドが呼び出される。外部からオブジェクト参照を使って呼び出すのと同様の振る舞いをするが、クラス内部から見ると「自分自身の機能を使う」という意図が明確になる。
自身を引数として他のメソッドに渡す
あるオブジェクトのメソッドが、現在実行中のインスタンス自身を別のオブジェクトのメソッドの引数として渡す必要がある場合に使用する。
INVOKE 他のオブジェクト参照 "メソッド名" USING SELF
これにより、現在のインスタンスへの参照が、指定されたメソッドの引数として渡される。これは、例えば「このオブジェクトの情報をあの監視オブジェクトに登録する」といったシナリオで非常に有効だ。
4. サンプルプログラム: SELFを使った計算処理
それでは、実際にSELFを使った簡単なサンプルプログラムを見てみよう。ここでは、数値を持つ`Calculator`クラスを作成し、その内部でSELFを使って自身の別のメソッドを呼び出す例を示す。
Calculator.cbl (クラス定義)
IDENTIFICATION DIVISION.
CLASS-ID. Calculator INHERITS BASE.
- クラスIDを定義。BASEクラスを継承する。
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CURRENT-VALUE PIC 9(5) VALUE ZERO.
- このインスタンスが保持する現在の値を格納するインスタンス変数。
PROCEDURE DIVISION.
- SET-VALUEメソッド: 現在の値を設定する
METHOD-ID. "SET-VALUE".
LINKAGE SECTION.
01 LS-NEW-VALUE PIC 9(5).
PROCEDURE DIVISION USING LS-NEW-VALUE.
MOVE LS-NEW-VALUE TO WS-CURRENT-VALUE.
GOBACK.
END METHOD "SET-VALUE".
- ADD-VALUEメソッド: 現在の値に指定された値を加算する
METHOD-ID. "ADD-VALUE".
LINKAGE SECTION.
01 LS-ADD-AMOUNT PIC 9(5).
PROCEDURE DIVISION USING LS-ADD-AMOUNT.
ADD LS-ADD-AMOUNT TO WS-CURRENT-VALUE.
GOBACK.
END METHOD "ADD-VALUE".
- DISPLAY-VALUEメソッド: 現在の値を画面に表示する
METHOD-ID. "DISPLAY-VALUE".
PROCEDURE DIVISION.
DISPLAY "現在の値: " WS-CURRENT-VALUE.
GOBACK.
END METHOD "DISPLAY-VALUE".
- ADD-AND-DISPLAYメソッド: 値を加算した後、SELFを使って自身の
- DISPLAY-VALUEメソッドを呼び出す
METHOD-ID. "ADD-AND-DISPLAY".
LINKAGE SECTION.
01 LS-ADD-AMOUNT PIC 9(5).
PROCEDURE DIVISION USING LS-ADD-AMOUNT.
- まず、指定された値を現在の値に加算する
ADD LS-ADD-AMOUNT TO WS-CURRENT-VALUE.
- ここがポイント!SELFを使って、このインスタンス自身の
- "DISPLAY-VALUE"メソッドを呼び出す。
- これにより、加算後の値を表示する処理を、自身のメソッドに任せている。
INVOKE SELF "DISPLAY-VALUE".
GOBACK.
END METHOD "ADD-AND-DISPLAY".
END CLASS Calculator.
Main.cbl (呼び出し側プログラム)
IDENTIFICATION DIVISION.
PROGRAM-ID. Main.
- メインプログラムIDを定義。
DATA DIVISION.
WORKING-STORAGE SECTION.
01 OREF-CALCULATOR OBJECT REFERENCE Calculator.
- Calculatorクラスのインスタンスを参照するためのオブジェクト参照。
01 WS-INITIAL-VALUE PIC 9(5) VALUE 100.
- 初期値として設定する数値。
01 WS-ADD-AMOUNT PIC 9(5) VALUE 50.
- 加算する数値。
PROCEDURE DIVISION.
- Calculatorインスタンスを生成する
INITIALIZE OREF-CALCULATOR.
INVOKE Calculator "NEW" RETURNING OREF-CALCULATOR.
DISPLAY "--- CALCULATORの初期化と値設定 ---".
- SET-VALUEメソッドで初期値を設定
INVOKE OREF-CALCULATOR "SET-VALUE" USING WS-INITIAL-VALUE.
- 現在の値を表示
INVOKE OREF-CALCULATOR "DISPLAY-VALUE".
DISPLAY "--- SELFを使わない加算と表示 (参照用) ---".
- ADD-VALUEメソッドで加算
INVOKE OREF-CALCULATOR "ADD-VALUE" USING WS-ADD-AMOUNT.
- その後、別途DISPLAY-VALUEメソッドを呼び出して表示
INVOKE OREF-CALCULATOR "DISPLAY-VALUE".
DISPLAY "--- SELFを使った加算と表示 ---".
- ADD-AND-DISPLAYメソッドを呼び出す。
- このメソッド内でSELFを使ってDISPLAY-VALUEが自動的に呼び出される。
INVOKE OREF-CALCULATOR "ADD-AND-DISPLAY" USING WS-ADD-AMOUNT.
- インスタンスの破棄(環境によっては不要な場合もあるが、明示的に行う習慣を)
INVOKE OREF-CALCULATOR "FINALIZE".
GOBACK.
実行結果例:
--- CALCULATORの初期化と値設定 ---
現在の値: 00100
--- SELFを使わない加算と表示 (参照用) ---
現在の値: 00150
--- SELFを使った加算と表示 ---
現在の値: 00200
この例では、`ADD-AND-DISPLAY`メソッドの内部で`INVOKE SELF “DISPLAY-VALUE”`と記述することで、現在のインスタンスが持つ表示メソッドを呼び出している。これにより、加算処理と表示処理が密接に連携し、カプセル化された形で機能を提供できるわけだ。
5. 応用・注意点: 現場で役立つ情報
応用例
- イベントハンドリング: GUIアプリケーションなどで、イベント発生時にイベントソースである自身を引数としてイベントハンドラに渡す。
- ファクトリーメソッド: クラスメソッド(STATICメソッド)とは別に、インスタンスメソッドとして自身のインスタンス(またはその派生クラスのインスタンス)を生成して返すような場合に、自身の情報を使ってオブジェクトを生成する。
- メソッドチェイン(流れるようなインターフェース): メソッドが処理を行った後、SELFを返却することで、`INVOKE obj “method1” INVOKE obj “method2″` のように連続してメソッドを呼び出すことができるようにする(JavaのStringBuilderが有名だ)。
注意点
- クラスメソッド(STATICメソッド)では使えない: SELFは「インスタンス自身」を指す予約語だ。クラスメソッドはインスタンスに依存しないため、クラスメソッドの内部でSELFを使用することはできない。もしクラス自身を指したい場合は、クラス名(例: `INVOKE MyClass “クラスメソッド名”`)を使うことになる。
- 無限再帰に注意: `INVOKE SELF “現在のメソッド名”`のように、現在のメソッド自身をSELFを使って呼び出すと、無限ループ(無限再帰)に陥る可能性がある。COBOLで再帰呼び出しを多用することは稀だが、意図しない再帰には十分注意してほしい。
- SELFはインスタンスへの参照: SELFは、あくまで現在のインスタンスへの参照(ポインタのようなもの)である。SELFを介してインスタンスの状態を変更すると、そのインスタンス全体に影響を与えることを常に意識しておく必要がある。
SELFは、COBOLでオブジェクト指向の恩恵を最大限に引き出すための強力なツールだ。これを使いこなすことで、よりモジュール化され、保守性の高い、そして何よりも「COBOLらしい」オブジェクト指向プログラムを記述できるようになるだろう。ぜひ、皆さんの現場で積極的に活用してほしい。

コメント