Dylan による実装

Dylan による実装


Dylan による実装例だ。2 さんにソースコードをいただきました。ありがとうございました。

この例では、リクエストを関数として与えている。send-request メソッドの中で、対象となるオブジェクトがそのリクエストを処理できるかどうか判断して、そのメソッドを呼び出すか、次のオブジェクトに渡すか決定するんだ。



<handler> クラス

// チェインのための <handler> クラス
// successor というスロット(インスタンス変数)を持つ
// <handler> を make するときに、「successor:」という
// キーワードで successor を指定できる
// 特に指定しない時は #f (false) を渡す

define class <handler> (<object>)
 slot successor :: false-or(<handler>),
 init-keyword: #"successor",
 init-value: #f;
end class;


send-request メソッド

// リクエストを送る
// リクエストは関数として与えられる
// メソッドを処理できる時、それを呼び出す。
// メソッドを処理できないが successor はある時は、
// successor に対してリクエストを送る
// メソッドも successor も無い時、エラーメッセージを出す
define method send-request (
 f :: <function>, h :: <handler>, #rest args)
 case
  apply(applicable-method?, f, h, args)
   => apply(f, h, args);
  h.successor ~= #f
   => apply(send-request, f, h.successor, args);
  otherwise => format-out("error: no handler\n");
 end case;
end method;

<button> クラス

// <button> クラス
define class <button> (<handler>) end;

define method help(b :: <button>)
 format-out("%=: help\n", b);
end;

<dialog> クラス

// <dialog> クラス
define class <dialog> (<handler>) end;

define method print(d :: <dialog>, num :: <integer>)
 format-out("%=: print %d papers\n", d, num);
end;

<application> クラス

// <application> クラス
define class <application> (<handler>) end;

define method preview(a :: <application>)
 format-out("%=: preview\n", a);
end;

main 関数

define function main(name, arguments)
 // インスタンスの作成
 let app = make(<application>);
 let dlg = make(<dialog>, successor: app);
 let btn = make(<button>, successor: dlg);

 // リクエストを送る。
 send-request(help, btn);
 send-request(print, btn, 3);
 send-request(preview, btn);

 exit-application(0);
end function main;

main(application-name(), application-arguments());

これだと、新しいハンドラの追加を send-request の変更なしに行えるわけだ。