デリゲートはメソッドへの参照を保持するクラスであり、インスタンス メソッドの場合は、そのメソッドを呼び出せるオブジェクトとなる。
デリゲート クラスのインスタンスが作成されると、保存されたインスタンス上の参照先メソッドが呼び出される場所で呼び出せるようになる。
1 つのデリゲート型に保持できるのは特定の署名のメソッドへの参照のみであるため、デリゲートの作成と呼び出しにおいて型の安全性が保たれる。
COBOL でデリゲートを定義する際には、DELEGATE-ID キーワードと、署名を指定する PROCEDURE DIVISION ヘッダーを使用する。たとえば、文字列パラメーターを持ち、binary-long を返すデリゲートは、次のように宣言する。
delegate-id MyDelegate. procedure division using by value s1 as string returning n1 as binary-long. end delegate.
メソッド グループは、キーワード METHOD を前に置くメソッド呼び出し式であり、パラメーターは取りません。メソッド グループが指定された場合、それは複数のメソッドのうち、指定された名前を持つ、指定されたクラスのメソッドを示します。
メソッド グループと特定のデリゲート型の間では暗黙変換が行われますが、メソッド グループで指定されたメソッドが、そのデリゲート型と互換性のある署名を持つ場合に限ります。
たとえば、上記で宣言したデリゲート MyDelegate のインスタンスを作成し、適切なメソッドを示すようにするには、次のように記述します。
01 d type MyDelegate. 01 c type Class1. ... set d to method c::m class-id Class1. method-id m. procedure division using by value s1 as string returning n1 as binary-long. end method. method-id m. procedure division using by value s1 as string s2 as string returning n1 as binary-long. end method. end class.
上記の例では、SET 文はメソッド m の最初のオーバーロードを自動的に選択します。これは、デリゲート型 MyDelegate の署名と互換性のある署名を持っているためです。
メソッド グループはメソッドのパラメーターとして使用することもできますが、そのメソッドが互換性のあるデリゲート型の引数を持つ場合に限ります。この場合にも、メソッド グループからデリゲート型への暗黙変換が行われ、そのデリゲートは対象メソッドにパラメーターとして渡されます。
デリゲートがコードの一部分をポイントするよう設定できます。その際、コードを正式にメソッドにする必要はありません。このようなコードは匿名メソッドと呼ばれ、キーワード DELEGATE および END-DELEGATE を使用して指定できます。
語 DELEGATE に語 USING および RETURNING を付加して、パラメーターの指定と値を返します。
次の例は、前述の例で作成したデリゲート MyDelegate に匿名メソッドを付加できることを示します。
01 d type MyDelegate.
set d to delegate using s1 as string
returning n1 as binary-long
set n1 to s1::Length
end-delegate.
デリゲートを作成した後で削除するには、キーワード RUN を使用し、後に続けてデリゲート名およびかっこで囲んだパラメーターを記述します。たとえば、上記で作成したデリゲート d を実行して結果を表示するには、次のように入力します。
display run d("Hello")
この文によって匿名メソッドが呼び出され、値 5 が返されます。その後、この値が表示されます。
delegate-id MyDelegate.
procedure division using by value s1 as string returning n1 as binary-long.
end delegate.
class-id a.
method-id main static.
01 d type MyDelegate.
01 c type Class1 value new Class1.
set d to method c::m
display run d("ABC")
set d to delegate using s1 as string
returning n1 as binary-long
set n1 to s1::Length
end-delegate
display run d("XYZ")
end method.
end class.
class-id Class1.
method-id m.
procedure division using by value s1 as string returning n1 as binary-long.
set n1 to size of s1 + 3
end method.
method-id m.
procedure division using by value s1 as string s2 as string returning n1 as binary-long.
end method.
end class.
1 つのデリゲートで複数のオブジェクト/メソッド ペアに対する参照を保持できます。このような場合、デリゲートが呼び出されると、各メソッドはデリゲートに追加された順序で呼び出されます。
次に例を示します。
class-id DelegateCombining.
method-id main static.
01 cd1 type D.
01 cd2 type D.
01 cd3 type D.
01 c type C value new C.
set cd1 to method type C::M1
invoke cd1(-1)
set cd2 to method type C::M2
invoke cd2(-2)
set cd3 to cd2 + method type C::M1
invoke cd3(10)
set cd3 to method type C::M1 + cd3
invoke cd3(20)
set cd3 to cd3 + method c::M3
invoke cd3(30)
set cd3 to cd3 - method type C::M1
invoke cd3(40)
set cd3 to cd3 - method c::M3
invoke cd3(50)
set cd3 to cd3 - method type C::M2
invoke cd3(60)
set cd3 to cd3 - cd2
invoke cd3(60)
set cd3 to cd3 - cd1
try
invoke cd3(70)
catch
display "null reference exception caught"
end-try
set cd3 to cd3 - cd1
set cd1 to method type C::M1
set cd2 to method type C::M2
set cd3 to cd1 + cd2 + cd2 + cd1
invoke cd3(80)
set cd3 to cd3 - cd1
invoke cd3(90)
set cd3 to cd1 + cd2 + cd2 + cd1
set cd3 to cd3 - (cd1 + cd2)
invoke cd3(100)
set cd3 to cd1 + cd2 + cd2 + cd1
set cd3 to cd3 - (cd2 + cd2)
invoke cd3(110)
set cd3 to cd1 + cd2 + cd2 + cd1
set cd3 to cd3 - (cd2 + cd1)
invoke cd3(120)
set cd3 to cd1 + cd2 + cd2 + cd1
set cd3 to cd3 - (cd1 + cd1)
invoke cd3(130)
end method.
end class.
delegate-id D.
procedure division using by value i as binary-long.
end delegate.
class-id C.
method-id M1 static.
procedure division using by value i as binary-long.
display "C::M1 --> " i
end method.
method-id M2 static.
procedure division using by value i as binary-long.
display "C::M2 --> " i
end method.
method-id M3.
procedure division using by value i as binary-long.
display "C::M3 --> " i
end method.
end class.
イベントは、GUI 環境でキーが押されたなどの重要な事象の発生をクラスが通知するための手段である。
イベントを定義するには、キーワード EVENT をデリゲートのフィールドに追加する。例:
01 ChangeEvent type ChangeDelegate event public.
同じ型のデリゲート、または互換性のあるメソッド グループや匿名メソッドをイベントにアタッチできる。イベントを所有するクラスがバッキング デリゲートを呼び出す際に、これらは呼び出される。
イベントとそのバッキング デリゲートの関係は、プロパティとバッキング記憶域の関係に非常に似ている。
デリゲート、メソッド グループ、または匿名メソッドをイベントにアタッチするには、次のように ATTACH 文を使用します。
ATTACH {delegate-instance} TO event-expression
{method-group}
{anonymous-method}
次に例を示します。
01 names type myList.
01 MyDelegate type ChangeDelegate.
procedure division.
set names to new myList
attach method ListChanged to names::ChangeEvent
set MyDelegate to method ListChanged
attach MyDelegate to names::ChangeEvent
デリゲートまたはメソッド グループをイベントからデタッチするには、次のように DETACH 文を使用します。
DETACH {delegate-instance} FROM event-expression
{method-group}
次に例を示します。
detach MyDelegate from names::ChangeEvent
detach method ListChanged from names::ChangeEvent