AppleScript でクラスベースオブジェクト指向プログラミング

Table of Contents

Introduction

AppleScript でクラスベースのオブジェクト指向プログラミングを行う方法を紹介するぜ。

AppleScript でも「クラス」という言葉が使われるけど、他のオブジェクト指向言語(C++ とか Objective-C とか)で使われる「クラス」とは意味合いがちょっと違う。多くのオブジェクト指向言語で言うオブジェクトのひな形としてのクラスは、AppleScript には無いんだけど、それを スクリプトオブジェクトで作っちゃう方法を解説します。

オブジェクトのひな形としてのクラスを導入すると、いいことがいっぱいある。似たようなオブジェクトを、効率よくたくさん生成できるようになり、メモリの使用量を劇的に減らせる。書くコードも効率的になると思う。その結果、オブジェクトが飛び交う本格的オブジェクト指向プログラミングができるようになる。また、ライブラリを作る上でとっても有用です。

オブジェクトとクラス

まずは、言葉の定義から確認しよう。オブジェクト指向プログラミングでいうオブジェクトとは、「自分が何ができるか知っているデータ」のことであり、クラスとはオブジェクトのひな形であるということでよいかな?

AppleScript でも、オブジェクトとかクラスとかいう用語は使われている。例えば、リストはリストクラスのオブジェクトであり、アプリケーションはアプリケーションクラスのオブジェクトということになっている。でも、これらはオブジェクト指向言語でいうオブジェクトとクラスとはちょっと違うぜ。何が違うかというと、AppleScript でいうオブジェクトにはメソッドが含まれていない。つまり、何が出来るかということを知らない。アプリケーションにはいくつかのコマンドが実装されていたりするけど、それらはそのアプリケーションで定義されている何らかのクラスに結びつけられている訳じゃない。だから、AppleScript にとってアプリケーションはオブジェクト指向言語でいうオブジェクトではなく、属性の集合体にすぎない。そして、クラスとは属性の集合体の種類にしか過ぎない。でも、その属性の集合体には継承関係があったりするので、単にクラスはデータの種類という訳でもないのがややこしいところ。まとめると、

プロトタイプベースとクラスベース

アプリケーションが提供するオブジェクトと違い、スクリプトオブジェクトはちゃんとしたオブジェクトだ。property がデータであり、そのデータを処理する為のメソッドをハンドラとして定義できる。AppleScript の世界でオブジェクト指向言語でいうオブジェクトはスクリプトオブジェクトだけだ。でも、オブジェクト指向言語でいうオブジェクトのひな形としてのクラスはないぜ。

AppleScript のスクリプトオブジェクトは生成過程を経ずに、いきなり存在できる。つまり、script ~ end script と書いたら、もうそれはオブジェクトが存在している。似たオブジェクトが欲しい場合は、すでに存在しているオブジェクトを複製する。このように、クラスを経由せずに既存のオブジェクトのコピーでオブジェクトを生成するやり方をプロトタイプベースという。プロトタイプベースの良い所は、クラスからオブジェクト生成というプロセスを省けること。使いたいオブジェクトがひとつ、ふたつと少ない場合はお手軽でよろしい。でも、不都合な点もいくつかある。実際、よくつかわれているオブジェクト指向言語のほとんどがクラスベースのオブジェクトシステムを採用している。

プロトタイプベースの既存のオブジェクトのコピーによるオブジェクトの生成は、一見、簡便でわかりやすいと思うかもしれない。しかし、AppleScript の場合は property だけでなくハンドラまでコピーされちゃうから、めちゃめちゃ効率が悪いぜ。普通はハンドラの実装はどこかに一つだけあって複数のオブジェクトから共有されればいいでしょう? でも、copy すると、property が複製されるにとどまらず、ハンドラも、継承している親オブジェクトも、何もかもコピーされちゃうんだぜ。

一方、クラスベースのオブジェクト指向言語では、メソッドはクラスに実装されており、オブジェクトはどのクラスに所属しているかだけを知っている。クラスによって、オブジェクト間でメソッドの実装を共有できている訳だ。

これを AppleScript のスクリプトオブジェクトで表現しよう。オブジェクト自身は property だけを持っていて、メソッド(ハンドラ)を実装したスクリプトオブジェクトを継承すればよい。

そして、複数の同種のオブジェクトが必要な場合、コンストラクタメソッドを経由してオブジェクトを生成した方がいい。copy コマンドによる複製だとオブジェクトの初期化に一手間必要になる。すると、オブジェクトのコピー及び初期化処理をまとめたハンドラを用意することになる。もう、これはコンストラクタメソッドだよね。

クラスを表現したスクリプトオブジェクトをクラスオブジェクトと呼ぶことにしよう。クラスオブジェクトの用件をまとめるぜ。

スクリプトオブジェクトによるクラスの実装

クラスの用件がはっきりしたので、早速、クラスオブジェクトの例をいきなりお見せしちゃう。

script ClassObject
on display_msg()
display alert my _msg
end display_msg

on make
set a_class to me
script Instance
property parent : a_class
property _msg : "hello"
end script
end make
end script

set x to make ClassObject
x's display_msg()

このサンプルの要点をまとめる。

という感じでわかるだろうか。

ところで、Instance スクリプトオブジェクトで、わざわざ property parent : a_class としている。実は、上のスクリプトでは、わざわざ parent を明示しなくてもちゃんと動く。parent の指定を省略すると、スクリプトオブジェクトはそれが定義されてたスクリプトオブジェクトを継承するからね。なんで、こんなことをしているかというと、ClassObject を継承したサブクラスを作る時に、 set a_class to meproperty parent : a_class が必要になってくる。

サブクラスの作り方

次に、サブクラスの作り方です。AppleScript には、言語レベルでクラスの機能がないものだから、いろいろを気をつけなければいけないことがあります。まずは、サンプルを。

script ClassObject
on display_msg()
display alert my _msg
end display_msg

on make
set a_class to me
script Instance
property parent : a_class
property _msg : "hello"
end script
end make
end script

script SubClassObject
property parent : ClassObject

on display_msg2()
display alert my _msg2
end display_msg2

on make
set self to continue make
script SubClassInstance
property parent : self
property _msg2 : "I'm subclass instance."
end script
end make
end script

set x to make SubClassObject
x's display_msg()
x's display_msg2()

要点をまとめます。

継承関係は、次の図のようになります。

以上で、本邦初公開、スクリプトオブジェクトでのクラスの作り方の説明はおしまいです。僕が開発した自慢のテクニックです。知っておくと規模の大きなスクリプトを作る時に絶対に役に立つはずです。

XModules で公開している AppleScript ライブラリの多くは、このテクニックを使ってクラスの概念を導入しています。もし、ご興味があればソースコードを覗いてみてください。