4D v16.3

プロジェクトメソッド

ホーム

 
4D v16.3
プロジェクトメソッド

プロジェクトメソッド  


 

 

プロジェクトメソッドには、適切な名前を付ける必要があります。フォームメソッドやオブジェクトメソッドはフォームやオブジェクトと密接に関連付けられていますが、プロジェクトメソッドはどこにでも使用できます。データベースの特定のオブジェクトに付属しているわけではありません。プロジェクトメソッドはその実行方法や使用方法に応じて、次のような役割を果たします:

  • メニューメソッド
  • サブルーチン、関数
  • プロセスメソッド
  • イベント処理メソッド
  • エラー処理メソッド

これらの用語はプロジェクトメソッドを、それがなんであるかで識別するのでなく、何を行うで識別しています。

メニューメソッドは、カスタムメニューから呼び出されるプロジェクトメソッドです。これは、ユーザのアプリケーションの流れを管理します。メニューメソッドは、必要とされる場所での分岐、フォームの表示、レポートの生成、ユーザデータベースの一般的な管理といった制御を行います。

サブルーチンは、処理の下請け的なプロジェクトメソッドです。他のメソッドから呼ばれて、リクエストされた処理を実行します。関数は、呼び出し元のメソッドに値を返すサブルーチンです。

プロセスメソッドは、プロセスの開始時に呼び出されるプロジェクトメソッドです。このプロセスは、プロセスメソッドが実行されている間だけ存続します。プロセスに関する詳細はの節を参照してください。メニューに属するメニューメソッドのプロパティとして新規プロセス開始をチェックした場合も、プロセスメソッドとして開始されます。

イベント処理メソッドは、イベントを処理するプロセスメソッドとして、分離されたプロセス内で実行されます。通常、開発者はイベント管理の大部分を4Dに任せます。例えば、データ入力中、4Dがキーストロークやクリックを検出し、それから正しいオブジェクトとフォームメソッドを呼び出します。このため開発者は、これらのメソッド内でイベントに対し適切に応答できるのです。一方、開発者がイベントを直接操作したい場合があります。例えば(レコードをブラウズするループ等)処理時間の長い操作を実行する場合、「Ctrl+.(ピリオド)」キー(Windows)や「command+.(ピリオド)」キー(Macintosh)を押して、その操作への割り込みを行いたいとします。この場合、開発者はイベント処理メソッドを使用する必要があります。詳細はON EVENT CALL コマンドの説明を参照してください。

エラー処理メソッドは、割り込みを実行するプロジェクトメソッドです。エラーや例外が起こる度に、エラー管理メソッドがインストールされたプロセス内で実行されます。詳細はON ERR CALL コマンドの説明を参照してください。

アプリケーションモードでカスタムメニューを選択すると、そのメニューに関連付けられたメニューメソッドが実行されます。メニューエディタを使用して、メニューコマンドにメソッドを割り当てます。メニューが選択されると、それに対応するメニューコマンドが実行されます。この手順は、データベースをカスタマイズする主要な方法の一つです。特定の処理を実行するメニューメソッドを割り当てたカスタムメニューを作成することで、データベースをカスタマイズすることができます。詳細は、4D Design Referenceのメニューエディタの説明を参照してください。

カスタムメニューコマンドにより、単一または複数の処理を実行することができます。例えば、データの入力処理を実行するメニューは、以下の2つの処理を実行するメソッドを呼び出すことができます。まず適切な入力フォームを表示します。次にユーザがキャンセルするまでの間ADD RECORD コマンドによるデータ入力を繰り返します。

連続した処理の自動化は、プログラミング言語の強力な機能の1つです。カスタムメニューを使用すると、処理を自動化することができ、データベースのユーザにより多くのガイダンスを提供することができます。

プロジェクトメソッドを作成すると、それは同じデータベースシステムの言語の一部になります。プロジェクトメソッドは、4Dに組み込まれたコマンドと同様に呼び出すことができます。このように使用されるプロジェクトメソッドをサブルーチンと呼びます。

サブルーチンは、以下のようなメリットがあります。

  • 重複したコードをなくす
  • メソッドの役割を明確にする
  • メソッドの変更を容易にする
  • コードをモジュール化する

例えば、顧客データベースがあるとします。データベースをカスタマイズしていくうちに同じ処理を繰り返し行うことに気づいたとします。それは顧客を検索してレコードを修正するという一連の作業です。そのコーディングは以下のようになっています:

  ` 顧客を検索
 QUERY BY EXAMPLE([Customers])
  ` 入力フォームを選択
 FORM SET INPUT([Customers];"Data Entry")
  ` 顧客のレコードを修正
 MODIFY RECORD([Customers])

サブルーチンを使用しなければ、顧客レコードの修正を実行するたびにコードを作成しなければなりません。10箇所で同じ処理が必要になると、同じコーディングを10回も行わねばなりません。サブルーチンを使用すれば1回コーディングするだけで済みます。これがコーディングの重複をなくすというサブルーチンの第一の利点です。

先ほど説明したコードがMODIFY CUSTOMERと呼ばれるメソッドであるならば、他のメソッドの中でメソッドの名前を使って実行できます。例えば、顧客のレコードを修正し、それからレコードをプリントするために、以下のようなメソッドを書くことができます:

 MODIFY CUSTOMER
 PRINT SELECTION([Customers])

この機能はメソッドを劇的にに簡素化します。例においてMODIFY CUSTOMERメソッドがどのように動作するか知る必要がなく、何を行うかを知っていればよいのです。これは、メソッドをサブルーチン化にすることにより処理内容が明確になる、二番目のメリットです。また、これにより作成したメソッドは4D言語を拡張したことになります。

このデータベース例で、顧客を検索する方法を変更する必要がある場合、10か所ではなく、たった1つのメソッドを変更するだけで済みます。これがサブルーチンを使うもう一つの理由です。

サブルーチンを使ってコードをモジュール化します。これはコードをモジュール(サブルーチン)に分割することを意味し、それぞれは論理的な仕事を実行します。アカウントデータベースの以下のコードを見てみましょう:

 FIND CLEARED CHECKS ` 決済済みの小切手を見つける
 RECONCILE ACCOUNT ` 口座の照合
 PRINT CHECK BOOK REPORT ` 出納記録の印刷

データベースを知らない人でも、このプログラムが何をしているかはわかります。各サブルーチンの処理手順を知る必要はありません。各サブルーチンは長く、複雑な処理で構成されていることもありますが、そのサブルーチンが何を実行するのかだけを知っていれば十分です。

プログラムを論理的な処理単位やモジュールにできるだけ分割することをお勧めします。

メソッドにデータを渡す必要がしばしば発生します。これは引数によって容易にできます。

引数は、メソッド内で行う処理に必要なデータです。引数という用語はこのマニュアルの随所で使用されています。引数は、4Dコマンドへデータを渡す場合にも使用します。以下の例は、文字列“Hello”という引数をALERTコマンドへ渡します:

 ALERT("Hello")

引数は、メソッドに対しても同じように渡すことができます。例えばメソッドDO SOMETHING が3つの引数を受け取る場合、このメソッドを呼び出すには以下のように書きます:

 DO SOMETHING(WithThis;AndThat;ThisWay)

引数は、セミコロン (;) で区切ります。

サブルーチン (呼び出されるメソッド) 内で、それぞれの引数の値は自動的に、順に番号が付けられたローカル変数 ($1, $2, $3...) に格納されます。ローカル変数の番号は、引数の順序を表わします。

  //DO SOMETHINGメソッドのコード
  //全ての引数がテキスト型とする
 C_TEXT($1;$2;$3)
 ALERT("I received "+$1+" and "+$2+" and also "+$3)
  //$1 には WithThis 引数が入る
  //$2 には AndThat 引数が入る
  //$3 には ThisWay 引数が入る

サブルーチン内で、他のローカル変数と同様にこれらの引数 ($1, $2...) を使用できます。しかしながら、引数として渡した変数の値を変更するコマンドを使用する場合 (例えばFind in field)、$1, $2などは直接使用することはできません。まず標準のローカル変数等にコピーする必要があります (例: $myvar:=$1)。

上級者向け注意: 4Dプロジェクトメソッドは同じ型の引数であれば、右側に不定数の変数を受け取ることができます。これらの変数を宣言するためには、${N}を引数として渡してコンパイラ指示子を使用します。ここでのNは最初の引数を指定します。例えば、C_LONGINT(${5}) という宣言は、4Dとコンパイラに、このメソッドは5番目の引数以降は不定数の倍超整数型の引数を受け取ることができる、ということを指示します。ここでCount parameters コマンドを使用するとそれらの引数をForループと引数関節参照シンタックスで受け取ることができます。詳細な情報については、Count parameters コマンドの例題2を参照してください。

引数は、その型によって、コピーによって、あるいは参照によって渡されます:

  • 引数がコピーによって渡される場合、ローカル変数/引数は呼び出しメソッドによって渡される実際のフィールド、変数、あるいは式ではありません。それらには渡された値のみが格納されます。これらのスコープはローカルであるため、引数の値がサブルーチン内で変更された場合、これらは呼び出しメソッド内の値は変更しません。
  • 引数が参照によって渡される場合、ローカル変数/引数は呼び出しメソッドによって渡される実際のソースフィールド、変数、あるいは式を指す参照を格納します。ローカル引数の値を変更すると、ソースの値も変更されます。

以下の表は、異なるタイプの要素がどのようにして渡されるかを表しています:

引数の型どのように渡されるか補足
スカラー型(数値、テキスト、日付など)のフィールド、変数、あるいは式値としてポインターを通して参照として渡すことも可能、以下を参照のこと
オブジェクト型のフィールド、変数あるいは式参照として以下の例題参照
コレクション型の変数あるいは式参照として
ポインター型の変数あるいは式参照としてメソッドにポインタを渡すを参照のこと
配列引数として直接は渡せませんポインターを通して参照として渡すことは可能、配列とポインタを参照のこと
テーブル引数として直接は渡せませんポインターを通して参照として渡すことは可能、ポインタを参照のこと

メソッドの引数として、スカラー型のフィールド、変数、あるいは式を使用する場合、値のコピーのみが渡されます。

$1$2... はローカル変数であるため、これらはサブルーチン内でのみ利用可能であり、サブルーチンの終わりにこれらは消去されます。このため、サブルーチンは、呼び出しメソッドレベルにおいては引数として渡された実際のフィールドや変数の値を変更することはできません。例えば:

  ` MY METHODからのコードの一部
  ` ...
 DO SOMETHING([People]Last Name) ` [People]Last Name が"williams"であるとする
 ALERT([People]Last Name)
 
  ` DO SOMETHINGメソッドのコード
 $1:=Uppercase($1)
 ALERT($1)

DO SOMETHING メソッドによって表示されたアラートボックスでは"WILLIAMS"と表示され、MY METHODメソッドによって表示されたアラートボックスでは"williams"と表示されます。メソッドは$1 引数の値をローカルな範囲で変更しましたが、これはメソッドによって渡された[People]Last Name フィールドの値には影響しません。

DO SOMETHING メソッドがフィールドの値を実際に変更するためには、2通りのやり方があります:

1. メソッドにフィールドを渡すのではなく、ポインターを渡す。この場合、以下のようにコードを書きます:

  ` MY METHODメソッドのコードの一部
  ` ...
 DO SOMETHING(->[People]Last Name) ` [People]Last Name が"williams"であるとする
 ALERT([People]Last Name)
 
  ` DO SOMETHINGメソッドのコード
 $1->:=Uppercase($1->)
 ALERT($1->)

ここでは引数はフィールドではなく、フィールドへのポインターです。そのため、DO SOMETHING メソッド内においては$1 引数はフィールドの値ではなく、フィールドへのポインターになっています。$1 引数によって参照されていたオブジェクト(上記コード内での$1-> )は実際のフィールドです。その結果、参照されたオブジェクトを変更すると、その影響はサブルーチンのスコープを超え、実際のフィールドも変更されます。この例題の中では、両方のアラートボックスに“WILLIAMS”と表示されます。

ポインターについてのより詳細な情報については、ポインタの章を参照してください。

2. DO SOMETHING メソッドに"何かさせる"より、メソッドを値を返すように書き直すこともできます。その場合、以下のようにコードを書くことができます:

  ` MY METHODのコードの一部
  ` ...
 [People]Last Name:=DO SOMETHING([People]Last Name) ` [People]Last Name が"williams"であるとする
 ALERT([People]Last Name)
  ` Here the code of the method DO SOMETHING
 $0:=Uppercase($1)
 ALERT($0)

このサブルーチンによって値を返す2番目の方法は、"関数を使用"という言い方をします。これは次の段落に詳細な説明があります。

メソッドの引数としてオブジェクト型あるいはコレクション型の変数、式、フィールドを使用する場合、実際のソースの値への参照が渡されます。この場合、$1、$2... には値ではなく参照が格納されます。$1、$2... 引数の値をサブルーチン内で変更した場合、これらの変更はソースとなるオブジェクトやコレクションが使用されているところへと伝播します。これはポインターに対する原理と同じものですが、ただし$1、$2... 引数はサブルーチン内で参照を解錠する必要がありません。

例:

  //CreatePerson メソッドはオブジェクトを作成し引数として送る
 C_OBJECT($person)
 $person:=New object("Name";"Smith";"Age";40)
 ChangeAge($person)
 ALERT(String(OB get($person;"Age")))

  //ChangeAge メソッドは受け取ったオブジェクトのAge属性に10を加える
 C_OBJECT($1)
 OB SET($1;"Age";OB Get($1;"Age")+10)
 ALERT(String(OB get($1;"Age")))

CreatePerson メソッドを実行した場合、どちらのメソッドに置いても同じ参照が扱われているため、両方のアラートボックスにおいて”50”と表示されます。

4D Server: 同じマシン上で実行されないメソッド間で引数が渡された場合(例えばサーバー上で実行オプションが使用された場合など、プロジェクトメソッドプロパティ参照)、参照は利用できません。この場合は、参照の代わりにオブジェクトとコレクション引数のコピーが送られます。

  メソッドからデータを返すこともできます。値を返すサブルーチンを関数と呼びます。

値を返す4Dコマンドや4Dプラグインコマンドも関数と呼びます。

以下の行は、文字列のデータ長を返すLength関数を用いたステートメントです。このステートメントは、Length関数がMyLengthという変数に値を返します。

 MyLength:=Length("How did I get here?")

どのようなサブルーチンでも値を返すことができます。返す値をローカル変数$0に格納します。

例えばUppercase4という以下の関数は、始めの4文字を大文字に変換した文字列を返します:

 $0:=Uppercase(Substring($1;1;4))+Substring($1;5)

以下は、Uppercase4 関数を使用するメソッドの例です:

 NewPhrase:=Uppercase4("This is good.")

変数NewPhrase には“THIS is good.”が格納されます。

戻り値 $0はサブルーチン内でローカル変数です。サブルーチンの中では$0を通常のローカル変数と同様に使用できます。例えば、前例のDO SOMETHINGにおいて、$0は最初に大文字に変換した$1の値を割り当てられ、その後ALERT コマンドの引数として使われました。サブルーチンの中では、他のローカル変数と同じ方法で$0を使うことができます。サブルーチンが終わる時の$0の値を呼び出し元のメソッドに戻すのは4Dの役割です。

プロジェクトメソッドは、自分自身を呼び出すことができます。例えば:

  • メソッドAがメソッドBを呼び出し、メソッドBはメソッドAを呼び出します。
  • メソッドAは自身を呼び出すことができます。

これは再帰呼び出しと呼ばれています。4D言語は再帰呼び出しを完全にサポートしています。

例題を見てみましょう。以下のフィールドから成る[Friends and Relatives] テーブルがあります:
- [Friends and Relatives]Name
- [Friends and Relatives]ChildrensName

こ の例題では、フィールドの値は重複しない、すなわち同じ名前の人間はいないとします。名前を指定することで、以下のような文を作成します:“A friend of mine, John who is the child of Paul who is the child of Jane who is the child of Robert who is the child of Eleanor, does this for a living!”:

1. この文を以下のように作成できます:

 $vsName:=Request("Enter the name:";"John")
 If(OK=1)
    QUERY([Friends and Relatives];[Friends and Relatives]Name=$vsName)
    If(Records in selection([Friends and Relatives])>0)
       $vtTheWholeStory:="A friend of mine, "+$vsName
       REPEAT
          QUERY([Friends and Relatives];[Friends and Relatives]ChildrensName=$vsName)
          $vlQueryResult:=Records in selection([Friends and Relatives])
          If($vlQueryResult>0)
             $vtTheWholeStory:=$vtTheWholeStory+" who is the child of "+[Friends and Relatives]Name
             $vsName:=[Friends and Relatives]Name
          End if
       Until($vlQueryResult=0)
       $vtTheWholeStory:=$vtTheWholeStory+", does this for a living!"
       ALERT($vtTheWholeStory)
    End if
 End if

2. 以下の方法でも作成できます:

 $vsName:=Request("Enter the name:";"John")
 If(OK=1)
    QUERY([Friends and Relatives];[Friends and Relatives]Name=$vsName)
    If(Records in selection([Friends and Relatives])>0)
       ALERT("A friend of mine, "+Genealogy of($vsName)+", does this for a living!")
    End if
 End if

再帰関数Genealogy ofは以下の通りです:

  ` Genealogy of プロジェクトメソッド
  ` Genealogy of ( String ) -> Text
  ` Genealogy of ( Name ) -> Part of sentence
 
 $0:=$1
 QUERY([Friends and Relatives];[Friends and Relatives]ChildrensName=$1)
 If(Records in selection([Friends and Relatives])>0)
    $0:=$0+" who is the child of "+Genealogy of([Friends and Relatives]Name)
 End if

Genealogy ofメソッドが自分自身を呼び出していることに注目してください。

最初に挙げた方法は反復性のアルゴリズムです。2番目に挙げた方法は再帰呼び出しのアルゴリズムです。

前述の例題のようなコードを実装する場合、反復性や再帰呼び出しを使用してメソッドを書くことができるということに注目してください。一般的に、再帰呼び出しは、より明瞭で、読みやすく、維持しやすいコードを提供します。ただし、この使用は必須ではありません。

4D内での再帰呼び出しの代表的な使用方法は以下の通りです:

  • 例題と同じく、お互いに関連するテーブル内でのレコードの取り扱い。
  • FOLDER LISTコマンドとDOCUMENT LISTコマンドを使用して、ディスク上にあるドキュメントとフォルダをブラウズする。フォルダにはフォルダとドキュメントが含まれており、サブフォルダはまたフォルダとドキュメントを含むことができます。

重要: 再帰呼び出しは、必ずある時点で終了する必要があります。例えばGenealogy ofメ ソッドが自身の呼び出しを止めるのは、クエリがレコードを返さないときです。この条件のテストをしないと、メソッドは際限なく自身を呼び出します。 (メソッド内で使用される引数やローカル変数と同様に) 再帰呼び出しを行う容量が一杯になると、最終的に4Dは“スタックがいっぱいです”エラーを返します 。



参照 

データベースメソッド
メソッド
制御フロー

 
プロパティ 

プロダクト: 4D
テーマ: プログラミング言語の構成要素

 
履歴 

 
ARTICLE USAGE

ランゲージリファレンス ( 4D v16)
ランゲージリファレンス ( 4D v16.1)
ランゲージリファレンス ( 4D v16.2)
ランゲージリファレンス ( 4D v16.3)