RealBasic University

このコラムはStone Table Softwareのオーナーであり、またREALbasic Developerの編集者でもあるMarc Zeedar氏により書かれたものを、著者の許可を得て翻訳したものです。この翻訳はHREM Researchにより提供されています。この日本語版へのご意見はRBU-Jまでご連絡下さい。

URL: http://www.applelinks.com/rbu/080/
INDEXに戻る

OOP University:パート 4

私は前回、オブジェクトが何であるかを説明しました。今回は、あまり議論されることのないオブジェクトの重要な違いを見ていくことにしましょう。私はクラスとオブジェクトの命名の重要性を明らかにすることで、これを行っていこうと思います。

名称の重要性

クラスの構造は、特性(characteristics)を継承するというその性質から、とても複雑になります(猫の小さなテーブルさえも、複雑になっていきます!)。親クラス、子クラス、孫クラスのどれもが独自の特性を持っています。あなたが様々なクラスのインスタンスを作成し始めれば(前出のmischiefInstancemayhemInstanceなど)、すぐに混乱してしまうでしょう。

OOPの初心者として、クラスやオブジェクトを一貫した論理的な方法で命名することは、極めて重要です。クラスやオブジェクトを混乱することから、複雑な問題が発生してきます。

例えば、このクラスの定義を見てみましょう。オブジェクトは次のように使われています:

  
Class TVobject
dim on as boolean
dim channel as integer
dim pip as boolean
dim screensize as integer
end Class

sub action
dim myTV as TVobject

myTV = new TVobject
myTV.screensize = 32
myTV.pip = true
myTV.on = true
myTV.channel = 823
...
end action

見てすぐに、私は大きな問題に気がつきました。このクラスを"TVobject"とすることで、自らが混乱してしまいます。"TVobject"はオブジェクトではありません。それはクラス(構造、定義、またはそれをどう見るかに依存する記述)です。そこには大きな違いがあります(詳細は次回のレッスンで説明しましょう)。基本的に設計図と建物を混乱しています!(クラス = 設計図、オブジェクト = 建物)

クラスはオブジェクトの構造を定義しますが、それ自身はオブジェクトではありません。より判りやすくするには、次のように定義することです:

  
Class tvClass
dim on as boolean
dim channel as integer
dim pip as boolean
dim screensize as integer
end Class

sub action
dim myTVInstance as tvClass

myTVInstance = new tvClass
myTVInstance.screensize = 32
myTVInstance.pip = true
myTVInstance.on = true
myTVInstance.channel = 823
...
end action

クラスであり、オブジェクトではないことを明確にするために、私はクラスの定義には"class"の用語を好んで使います。この一連のチュートリアルの目的のため、オブジェクトのインスタンスとして"instance"を使用します。一般的に、あなたの定義するオブジェクトは自分自身で判断できれば、そのように明確に区別することは必ずしも必要ではありませんが、オブジェクトに取り組み始めたばかりならば、明確に区別して頭に叩き込むことが重要になってきます。

ではインスタンス(instance)とは何でしょうか?それは今回説明するには少し複雑なので、次回のレッスンで取り上げることにしましょう。

次週

複雑なインスタンスについて取り組みます。

Letters

AppとModuleの違いについて、すばらしい質問をしてくれたThomas Ferrellさんからの手紙がきています:

こんにちは

私にとってRBの特に判りづらい所は、AppとModuleの包含関係についてです。Moduleにはグローバルを保存することができ、そしてAppはAppleScriptの基本的な整合性のために必要だと学びました(メニューについては―Appに属するのか、windowに属するのか明確ではありませんが)。しかし、何が加えられるべきで何が必要なのかを示すプログラム全体の構造のガイドとなるようなものがあるべきでしょう。いずれにしても、Appとは何でしょうか――すべてのプログラムはAppだと思うのですが。フローチャートは参考になりますが、いくつかの解説付きの例題も悪くないと思います。RBデベロッパーズ・ガイドではModuleについての章がありますが、他の場所で定義された関数が問題を引き起こす可能性があるということと、Moduleはプログラム全体の構造の枠に組み込まれるべきであるということが、2つの段落で簡単に述べられているだけです。

それでは。
Tom

Tomさん、すばらしい質問です!幸運にも、それは簡単に説明できます。

モジュールは、コードの集まりです。そこには定数メソッド、そして属性が含まれます。それらはすべてグローバルです:すなわち、他のすべてのプログラムで利用することができます。

moduleの概念は、他のプログラムで再利用できるルーチンを含むべきであるということです。例えば、読み込み、解析、選択オプションの保存に使うためのシステムの基本をなす"prefsModule"があるとしましょう。私はこれをプログラムにインストールし、それを特定のアプリ用に簡単にカスタマイズすることができます。

Finderへドラッグすることで、moduleをエキスポートできます(REALbasicはmoduleのデータを含むファイルを作成します)。Finderから現在のプロジェクト・ウィンドウへmoduleファイルをドラッグすることによって、他のプログラムにmoduleをインポートすることができます。

RBU裏技

オプションとコマンド・キーを押しながら、moduleファイルをプロジェクトにドラッグすると、REALbasicはmoduleをコピーしないで、そこへリンクを貼ります。これは、ディスクからオリジナルのmoduleファイルを消去できないということを意味しますが、複数のプログラムが同時に同じmoduleを利用できるということを意味します。したがって、moduleのバグを修正したり、あるいはどこかを改良した場合は、そのmoduleを利用する他のすべてのプログラムが恩恵を受けます!

さて、"App"はもっと複雑です。

詳細

あなたがクラス・オブジェクトの"app"に慣れていない場合は、次のようにプロジェクトに追加してください:

ファイル・メニューから"New Class"を選択します。

プロジェクト・ウィンドウに挿入されたClass1の項目を選び、属性(Property)ウィンドウで名前をappに変更します。

次に属性ウィンドウで、appのSuperを"Application"にします(直接入力するか、またはリストから選択します)。

以上で、特別なapplicationイベントにアクセスするために、先ほど作成したappクラスを利用することができます(詳細は以下に)。

技術的には、appApplicationクラスのサブクラスです。それをサブクラス化する理由は、それに変更を加えることができるからです(例えば、属性、イベント、メソッド、その他の追加)。

デフォルトでは、すべてのREALbasicのアプリケーションは自動的にApplicationオブジェクトを持っています。ただそれは不可視です(それへのインターフェースがありません)。私は、REAL Software社がデフォルトで、すべての新しいプロジェクトにappクラスを含めれば、より簡潔で明確になると思っています。それを使用しないで、持つだけならば何も害はありませんし、使用するときにわざわざ手で追加する必要がないので好都合です。

デフォルトで含まれているApplicationオブジェクトは見ることができないので、それを変更することはできません。あなた独自のサブクラスを追加することによって、通常のApplicationクラス・オブジェクトの限定された機能を、自由に拡張することができます。

Appleイベントを処理したいときに、appクラスを追加する必要があるというあなたの指摘は当たっています(AppleScriptはAppleイベントを通じて通信します)。また、次のような他の利点もあります:

HandleAppleEventイベントは、プログラムに送られたAppleイベントの解析をする場所です。NewDocumentOpenDocumentは、ユーザが新しい文書を作成、あるいは既存の文書を開こうとするときに実行されるコードを置いておく場所です。UnhandledExceptionは、プログラム中に実行可能で処理されない例外(exception)エラーを処理するためのものです。

Appが独自のメニュー処理システムを持っていることで、混乱するとあなたは指摘しています。実は、これには簡単な説明があります。普通は、ほとんどのメニュー・ハンドラーはウィンドウ内に置きますね?それは、ほとんどの文書がウィンドウであり、真のオブジェクト指向のデザインでは、文書に結びついたメニューコマンドは文書オブジェクト(文書ウィンドウ)で処理することが望ましいからです。

しかし、すべてのウィンドウが閉じられたらどうでしょうか?メニューを処理する唯一の場所がウィンドウ・オブジェクトであるならば、すべてのウィンドウが閉じられたら、ユーザがメニューを扱う手段がなくなってしまうでしょう!

幸いにも、ウィンドウが閉じられた時に使用したいメインコマンド――"Quit"――はREALbasicによって自動的に処理されます。したがって、少なくとも特に何もすることなしに、ユーザはプログラムから抜け出すことができます。しかし、新しいファイルを作成したり、既存のファイルを開いたり、あるいは選択項目を設定したりということについてはどうなってしまうのでしょうか?これらの事柄は、ユーザが既に開いている文書を介さないで行いたいことでしょう。

アプリケーションによって、文書が開かれていないときの設定(アプリケーション設定)や文書固有の設定(文書設定)のような、異なる選択をしたいこともあるでしょう。これを例証するために、私はデモンストレーションのREALbasicプロジェクト(appdemo.sit)を作成しました。それは表示目的のためだけで、選択は実際には保持されないことに注意して下さい。

このアプリケーションがどのように機能するかを示すフローチャートをここに示します。

お分かりのように、ウィンドウのメニュー・ハンドラーが最優先されています。したがって、ウィンドウが開かれる時に、ウィンドウのfilePreferencesメニュー・ハンドラーが実行されます。メニュー・ハンドラーはデフォルトでfalseを返すので、そのハンドラー内でtrueを返さないと、appメニューイベントを処理することになります:

デモ・プログラムで、上のreturn trueの行をコメント・アウトして、何が起こるのか見てみましょう!

ウィンドウがメニュー・イベントを処理しない場合(あるいは開いているウィンドウがない場合)は、REALbasicはapplicationオブジェクト(作成していれば、appクラスがそれです)にイベントを渡し、それを処理させます(可能であれば)。これによって文書の設定ダイアログ(ローカル)、そしてアプリケーション設定の別のダイアログ(グローバル)を表示させることができます。

いくつかのメニュー・コマンド(例えば"Close window"コマンド)はapplicationオブジェクトで処理するには不適切であることに注意しましょう。applicationオブジェクトでそれを処理したい場合は、まず始めに開いているウィンドウがあるかをチェックし、それからユーザが閉じようとしているウィンドウはどれであるか見つけ出さなければなりません。ウィンドウ自身にそれを置くことで、物事をかなり単純にすることができます。結局、ウィンドウが存在すれば(そのコードを実行するためには、そうでなければなりません)、少なくともひとつの開いているウィンドウがあり、Closeコマンドが有効なので、現在のウィンドウを閉じることができます。すべてのウィンドウが閉じられたら、Closeメニュー・コマンドのある文書ウィンドウはありません。よって、appオブジェクトは何もする必要がなくなります(Closeメニュー・コマンドは無効になります)。

Closeウィンドウのメニュー・ハンドラーを、appオブジェクトの内部に置くのが不適切であるのと同様に、ウィンドウの内部に"new"や"open"ハンドラーを置くのはバカげています。第一に、app内部にコードがなく、開いているウィンドウもなければ、新しい文書を作成したり開いたりする方法がないでしょう!第二に、app内部にコードが必ず存在するので、なぜウィンドウ内にメニュー・ハンドラーのコードを複製するのでしょうか?

この二つのシステムがどのように作業の流れを分かち合うか見ることから始めてみましょう。ウィンドウはappを上書きしますが、開かれているウィンドウがなければappはそのままです。時々、メニュー・コマンドを処理するためにどちらか一方が必要ですが、両者に少し機能の違いを持たせて動作させたい場合(選択の状況のように)もあるでしょう。

異なるウィンドウが異なるメニュー・ハンドラーをサポートする時、前面のウィンドウ(アクティブ・ウィンドウ)のハンドラーが使用されるものとなります。

詳細

コントロールがサブクラス化でき、これらの新しいオブジェクトが独自のメニュー・ハンドラーを持つことができることを覚えているでしょう。コントロールが独自のメニュー・ハンドラーを持つ時、それはウィンドウのメニュー・ハンドラーよりも最優先されます。したがって優先順位は次のようになります。

  
control > window > app

これを理解する最もよい方法は、例を見ることです。サブクラスがどのように独自のメニュー・ハンドラーを使用するか確認するために、私の作成した"select all editField"(saeditfield.sit)を見てください。

appのActivateDeactivateイベントは、メニューの処理システムと同じように機能することに気づくでしょう:ウィンドウが開けば、それらもまたActivateDeactivateイベントを持ちますが、何も開かれていなければ、appオブジェクトなしではプログラムが起動しているかを知る方法はありません。

実際、これを判りづらくしている要因は、あなたがある時にはappクラスを含むプロジェクトを作成し、またある時にはそれを含まないプロジェクトを作成するからです。実際にはそれはほぼ常に必要で、それが使用されなくても何も害はありませんので、いつもappクラス含めておくのはどうでしょうか?あなたのプロジェクトに、appクラスを追加することを習慣づけましょう。

ここをクリックすれば、appdemo.sitがダウンロードできます。


RBU-Jの通知サービス!コラムが発表されるたびに日本語版REALbasic Universityのお知らせの emailがあなたに届きます。登録・削除は ここ から。

INDEXに戻る