AppleScript でクラスベースのオブジェクト指向プログラミングを行う方法を紹介するぜ。
AppleScript でも「クラス」という言葉が使われるけど、他のオブジェクト指向言語(C++ とか Objective-C とか)で使われる「クラス」とは意味合いがちょっと違う。多くのオブジェクト指向言語で言うオブジェクトのひな形としてのクラスは、AppleScript には無いんだけど、それを スクリプトオブジェクトで作っちゃう方法を解説します。
オブジェクトのひな形としてのクラスを導入すると、いいことがいっぱいある。似たようなオブジェクトを、効率よくたくさん生成できるようになり、メモリの使用量を劇的に減らせる。書くコードも効率的になると思う。その結果、オブジェクトが飛び交う本格的オブジェクト指向プログラミングができるようになる。また、ライブラリを作る上でとっても有用です。
まずは、言葉の定義から確認しよう。オブジェクト指向プログラミングでいうオブジェクトとは、「自分が何ができるか知っているデータ」のことであり、クラスとはオブジェクトのひな形であるということでよいかな?
AppleScript でも、オブジェクトとかクラスとかいう用語は使われている。例えば、リストはリストクラスのオブジェクトであり、アプリケーションはアプリケーションクラスのオブジェクトということになっている。でも、これらはオブジェクト指向言語でいうオブジェクトとクラスとはちょっと違うぜ。何が違うかというと、AppleScript でいうオブジェクトにはメソッドが含まれていない。つまり、何が出来るかということを知らない。アプリケーションにはいくつかのコマンドが実装されていたりするけど、それらはそのアプリケーションで定義されている何らかのクラスに結びつけられている訳じゃない。だから、AppleScript にとってアプリケーションはオブジェクト指向言語でいうオブジェクトではなく、属性の集合体にすぎない。そして、クラスとは属性の集合体の種類にしか過ぎない。でも、その属性の集合体には継承関係があったりするので、単にクラスはデータの種類という訳でもないのがややこしいところ。まとめると、
アプリケーションが提供するオブジェクトと違い、スクリプトオブジェクトはちゃんとしたオブジェクトだ。property がデータであり、そのデータを処理する為のメソッドをハンドラとして定義できる。AppleScript の世界でオブジェクト指向言語でいうオブジェクトはスクリプトオブジェクトだけだ。でも、オブジェクト指向言語でいうオブジェクトのひな形としてのクラスはないぜ。
AppleScript のスクリプトオブジェクトは生成過程を経ずに、いきなり存在できる。つまり、script ~ end script と書いたら、もうそれはオブジェクトが存在している。似たオブジェクトが欲しい場合は、すでに存在しているオブジェクトを複製する。このように、クラスを経由せずに既存のオブジェクトのコピーでオブジェクトを生成するやり方をプロトタイプベースという。プロトタイプベースの良い所は、クラスからオブジェクト生成というプロセスを省けること。使いたいオブジェクトがひとつ、ふたつと少ない場合はお手軽でよろしい。でも、不都合な点もいくつかある。実際、よくつかわれているオブジェクト指向言語のほとんどがクラスベースのオブジェクトシステムを採用している。
プロトタイプベースの既存のオブジェクトのコピーによるオブジェクトの生成は、一見、簡便でわかりやすいと思うかもしれない。しかし、AppleScript の場合は property だけでなくハンドラまでコピーされちゃうから、めちゃめちゃ効率が悪いぜ。普通はハンドラの実装はどこかに一つだけあって複数のオブジェクトから共有されればいいでしょう? でも、copy すると、property が複製されるにとどまらず、ハンドラも、継承している親オブジェクトも、何もかもコピーされちゃうんだぜ。
一方、クラスベースのオブジェクト指向言語では、メソッドはクラスに実装されており、オブジェクトはどのクラスに所属しているかだけを知っている。クラスによって、オブジェクト間でメソッドの実装を共有できている訳だ。
これを AppleScript のスクリプトオブジェクトで表現しよう。オブジェクト自身は property だけを持っていて、メソッド(ハンドラ)を実装したスクリプトオブジェクトを継承すればよい。
そして、複数の同種のオブジェクトが必要な場合、コンストラクタメソッドを経由してオブジェクトを生成した方がいい。copy コマンドによる複製だとオブジェクトの初期化に一手間必要になる。すると、オブジェクトのコピー及び初期化処理をまとめたハンドラを用意することになる。もう、これはコンストラクタメソッドだよね。
クラスを表現したスクリプトオブジェクトをクラスオブジェクトと呼ぶことにしよう。クラスオブジェクトの用件をまとめるぜ。
クラスの用件がはっきりしたので、早速、クラスオブジェクトの例をいきなりお見せしちゃう。
このサンプルの要点をまとめる。
という感じでわかるだろうか。
ところで、Instance スクリプトオブジェクトで、わざわざ property parent : a_class としている。実は、上のスクリプトでは、わざわざ parent を明示しなくてもちゃんと動く。parent の指定を省略すると、スクリプトオブジェクトはそれが定義されてたスクリプトオブジェクトを継承するからね。なんで、こんなことをしているかというと、ClassObject を継承したサブクラスを作る時に、 set a_class to me と property parent : a_class が必要になってくる。
次に、サブクラスの作り方です。AppleScript には、言語レベルでクラスの機能がないものだから、いろいろを気をつけなければいけないことがあります。まずは、サンプルを。
要点をまとめます。
継承関係は、次の図のようになります。
以上で、本邦初公開、スクリプトオブジェクトでのクラスの作り方の説明はおしまいです。僕が開発した自慢のテクニックです。知っておくと規模の大きなスクリプトを作る時に絶対に役に立つはずです。
XModules で公開している AppleScript ライブラリの多くは、このテクニックを使ってクラスの概念を導入しています。もし、ご興味があればソースコードを覗いてみてください。