クラス
ここでは、InterSystems IRIS® データ・プラットフォームでクラスを定義および操作するための基本的な規則について説明します。
"オブジェクト" では、オブジェクトとオブジェクト・クラスについて説明します。
クラス定義は正式には ObjectScript の一部ではありません。むしろ、クラス定義の特定の部分内で ObjectScript を使用することができます (特に、メソッド定義内。ここでは、その他の実装言語を使用することもできます)。クラスを定義するために使用される構文は、クラス定義言語と呼ばれます。この構文については、ObjectScript とは別に説明されています。
クラス名とパッケージ
各 InterSystems IRIS. クラスは名前を持ち、その名前は、それが定義されているネームスペース内で一意である必要があります。完全なクラス名は、例えば、package.subpackage.subpackage.class のような、1 つ以上のピリオドで区切られた文字列です。短いクラス名は、この文字列内の最後のピリオドの後の部分であり、最後のピリオドの前の部分はパッケージ名です。
パッケージ名は単なる文字列ですが、ピリオドが含まれている場合、InterSystems IRIS 開発ツールは、ピリオドで区切られた各部分をサブパッケージとして処理します。統合開発環境 (IDE) およびその他のツールでは、便宜上、これらのサブパッケージはフォルダの階層として表示されます。
クラス定義の基本的なコンテンツ
InterSystems IRIS クラスの定義には、以下の項目を含めることができ、これらはすべてクラス・メンバと呼ばれます。
-
メソッド — インスタンス・メソッドとクラス・メソッド (他の言語では静的メソッドと呼ぶ) の 2 種類のメソッドがあります。多くの場合、メソッドはサブルーチンです。
-
パラメータ — パラメータは、このクラスによって使用される定数値を定義します。この値はコンパイル時に設定されます。
-
プロパティ — プロパティには、クラスのインスタンスのデータが格納されます。
-
クラス・クエリ — クラス・クエリは、クラスが使用できる SQL クエリを定義し、クエリ用のコンテナとして使用するクラスを指定します。
-
XData ブロック — XData ブロックは、クラスによって使用される、クラス内の整形式 XML ドキュメントです。
-
その他の種類のクラス・メンバ (永続クラスにのみ関連するメンバ)。
InterSystems IRIS クラス定義では、クラス定義言語 (CDL) を使用して、クラスとそのメンバを指定します。メソッド内部の実行可能コードの記述には、Python または ObjectScript を使用できます。
クラス定義には、キーワードを含めることができ、それらはクラス・コンパイラ動作に作用します。キーワードには、クラス全体に対して指定できるものと、特定のクラス・メンバに対して定義できるものがあります。これらのキーワードは、クラス・コンパイラが生成するコードに作用し、その結果、クラスの動作を制御します。
以下に、ObjectScript および Python で記述された簡単な InterSystems IRIS クラス定義とメソッドを示します。
Class MyApp.Main.SampleClass Extends %RegisteredObject
{
Parameter CONSTANTMESSAGE [Internal] = "Hello world!" ;
Property VariableMessage As %String [ InitialExpression = "How are you?"];
Property MessageCount As %Numeric [Required];
ClassMethod HelloWorld() As %String [ Language = objectscript ]
{
Set x=..#CONSTANTMESSAGE
Return x
}
Method WriteIt() [ Language = objectscript, ServerOnly = 1]
{
Set count=..MessageCount
For i=1:1:count {
Write !,..#CONSTANTMESSAGE," ",..VariableMessage
}
}
}
Class MyApp.Main.SampleClass Extends %RegisteredObject
{
Parameter CONSTANTMESSAGE [Internal] = "Hello world!" ;
Property VariableMessage As %String [ InitialExpression = "How are you?"];
Property MessageCount As %Numeric [Required];
ClassMethod MessageWrapper() As %String [ Language = objectscript ]
{
return ..#CONSTANTMESSAGE
}
ClassMethod HelloWorld() As %String [ Language = python ]
{
import iris
x = iris.cls("MyApp.Main.SampleClass").MessageWrapper()
return x
}
Method WriteIt() [ ServerOnly = 1, Language = python ]
{
import iris
CONSTANTMESSAGE = self.MessageWrapper()
count = self.MessageCount
print()
for i in range(count):
print(CONSTANTMESSAGE, self.VariableMessage)
}
}
以下の点に注意してください。
-
最初の行は、クラスの名前を指定します。MyApp.Main.SampleClass は完全なクラス名であり、MyApp.Main がパッケージ名、SampleClass が短いクラス名です。
IDE および他のユーザ・インタフェースでは、各パッケージはフォルダとして処理されます。
-
Extends はコンパイラ・キーワードです。
Extends キーワードは、このクラスが %RegisteredObjectOpens in a new tab のサブクラスであることを指定します。これは、オブジェクトをサポートするために用意されているシステム・クラスです。このサンプルのクラスでは 1 つのクラスのみを拡張していますが、他の複数のクラスを拡張することもできます。また、それらのクラスが他のクラスを拡張することもできます。
-
CONSTANTMESSAGE はパラメータです。慣例で、InterSystems IRIS システム・クラスのすべてのパラメータの名前はすべて大文字にします。これは、便利な慣例ですが、これに従う必要はありません。
Internal キーワードはコンパイラ・キーワードです。これは、このパラメータが内部であることを示し、クラス・ドキュメントで表示されないようにします。このパラメータは文字列値を持ちます。
クラス・パラメータには、ObjectScript を使用してアクセスする必要があります。このクラスの Python バージョンでは、ObjectScript クラス・メソッド MessageWrapper() を使用して、パラメータの値を返します。
-
Python からあらゆるクラス・メソッドにアクセスできます。iris.cls("Package.Class").classMethodName() 構文はあらゆるコンテキストで使用でき、self.classMethodName() 構文は Python インスタンス・メソッド内から使用できます。例では、両方の構文形式を示しています。
-
VariableMessage および MessageCount はプロパティです。As の後の項目は、これらのプロパティのタイプを示します。InitialExpression および Required はコンパイラ・キーワードです。
例で示しているように、InterSystems IRIS クラス・プロパティに ObjectScript または Python から直接アクセスできます。
-
HelloWorld() はクラス・メソッドであり、文字列を返します。これは As の後の項目によって示されます。
このメソッドは、クラス・パラメータの値を使用します。
-
WriteIt() はインスタンス・メソッドであり、値を返しません。
このメソッドは、クラス・パラメータの値と 2 つのプロパティの値を使用します。
ServerOnly コンパイラ・キーワードは、このメソッドが外部クライアントに投影されないことを意味します。
以下のターミナル・セッションは、このクラスの使用法を示しています。どちらのターミナル・シェルも、クラスの ObjectScript バージョンと Python バージョンで有効です。
TESTNAMESPACE>write ##class(MyApp.Main.SampleClass).HelloWorld()
Hello world!
TESTNAMESPACE>set x=##class(MyApp.Main.SampleClass).%New()
TESTNAMESPACE>set x.MessageCount=3
TESTNAMESPACE>do x.WriteIt()
Hello world! How are you?
Hello world! How are you?
Hello world! How are you?
>>> print(iris.cls("MyApp.Main.SampleClass").HelloWorld())
Hello world!
>>> x=iris.cls("MyApp.Main.SampleClass")._New()
>>> x.MessageCount=3
>>> x.WriteIt()
Hello world! How are you?
Hello world! How are you?
Hello world! How are you?
クラス・メソッド呼び出しのショートカット
ObjectScript を使用してクラス・メソッドを呼び出す場合、以下のシナリオではパッケージ (または上位パッケージ) を省略できます。
-
参照が 1 つのクラス内であり、参照されるクラスが同じパッケージまたはサブパッケージ内にある場合。
-
参照が 1 つのクラス内であり、そのクラスが IMPORT 指示文を使用して、参照されるクラスを含むパッケージまたはサブパッケージをインポートする場合。
-
参照が 1 つのメソッド内であり、そのメソッドが IMPORT 指示文を使用して、参照されるクラスを含むパッケージまたはサブパッケージをインポートする場合。
ObjectScript または Python からクラス・メソッドを呼び出す場合、以下のシナリオではパッケージ (または上位パッケージ) を省略できます。
-
%Library パッケージ内のクラスを参照している場合、これは特別に処理されます。クラス %Library.ClassName は %ClassName として参照できます。例えば、%Library.StringOpens in a new tab は %StringOpens in a new tab として参照できます。
-
User パッケージ内のクラスを参照している場合、これは特別に処理されます。例えば、User.MyClass は MyClass として参照できます。
インターシステムズでは、User パッケージにはクラスを提供していません。これは、ユーザが使用するために予約されています。
他の場合はすべて、常に完全なパッケージ名とクラス名を使用してクラス・メソッドを呼び出す必要があります。
クラス・パラメータ
クラス・パラメータは、指定されたクラスのすべてのオブジェクトに対して同じ値を定義します。まれに例外がありますが、この値は、クラスのコンパイル時に確立され、実行時に変更することはできません。クラス・パラメータは、以下の目的で使用します。
-
実行時に変更できない値を定義するため。
-
クラス定義に関するユーザ指定の情報を定義するため。クラス・パラメータは、単純な任意の名前と値の組み合わせです。この組み合わせを使用して、クラスに関する必要な情報を保存します。
-
プロパティとして使用する場合、さまざまなデータ型クラスの動作をカスタマイズするため (検証情報の提供など)。これについては、次のセクションで説明します。
-
使用するメソッド・ジェネレータ・メソッドに対して、パラメータ化された値を提供するため。
ObjectScript メソッド、Python メソッド、またはこれら 2 つの組み合わせが含まれる InterSystems IRIS クラスのパラメータを定義できます。以下に、いくつかのパラメータを持つクラスを示します。
Class GSOP.DivideWS Extends %SOAP.WebService
{
Parameter USECLASSNAMESPACES = 1;
/// Name of the Web service.
Parameter SERVICENAME = "Divide";
/// SOAP namespace for the Web service
Parameter NAMESPACE = "http://www.mynamespace.org";
/// let this Web service understand only SOAP 1.2
Parameter SOAPVERSION = "1.2";
///further details omitted
}
プロパティ
InterSystems IRIS には、以下の 2 種類のプロパティがあります。
-
属性 - 値を保持します。この値は、以下のいずれかです。
-
1 つのリテラル値。通常、データ型に基づきます。
-
オブジェクト値 (コレクション・オブジェクトとストリーム・オブジェクトがあります)。
-
多次元配列。これはあまり一般的ではありません。
プロパティという用語は、関連付けを保持するプロパティではなく、単に、属性のプロパティを示すことがよくあります。
-
-
リレーションシップ - オブジェクト間の関連付けを保持します。
ObjectScript メソッド、Python メソッド、またはこれら 2 つの組み合わせが含まれるクラスのプロパティを定義できます。ただし、Python メソッドからリレーションシップにアクセスすることはできません。このセクションでは、これらのバリエーションのいくつかを示すプロパティ定義を含むサンプル・クラスを示します。
Class MyApp.Main.Patient Extends %Persistent
{
Property PatientID As %String [Required];
Property Gender As %String(DISPLAYLIST = ",Female,Male", VALUELIST = ",F,M");
Property BirthDate As %Date;
Property Age As %Numeric [Transient];
Property MyTempArray [MultiDimensional];
Property PrimaryCarePhysician As Doctor;
Property Allergies As list Of PatientAllergy;
Relationship Diagnoses As PatientDiagnosis [ Cardinality = children, Inverse = Patient ];
}
以下に留意してください。
-
それぞれの定義では、As の後の項目はプロパティのタイプです。各タイプはクラスです。構文 As List Of は、特定のコレクション・クラスの省略表現です。
%StringOpens in a new tab、%DateOpens in a new tab、および %NumericOpens in a new tab はデータ型クラスです。
%StringOpens in a new tab は既定のタイプです。
-
Diagnoses は、リレーションシップ・プロパティであり、残りは属性プロパティです。
-
PatientID、Gender、BirthDate、および Age は、単純なリテラル値のみを格納できます。
-
PatientID は Required キーワードを使用するため、必須です。つまり、このクラスのオブジェクトは、このプロパティの値を指定しない場合、保存できません。
-
Age は、他のリテラル・プロパティとは異なり、ディスクに保存されません。これは、それが Transient キーワードを使用するためです。
-
MyTempArray は MultiDimensional キーワードを使用するため、多次元プロパティです。このプロパティは既定では、ディスクに保存されません。
-
PrimaryCarePhysician および Allergies は、オブジェクト値プロパティ です。
-
Gender プロパティ定義には、プロパティ・パラメータの値が含まれます。これらは、このプロパティが使用するデータ型クラスのパラメータです。
このプロパティの値は、M と F に制限されます。表示値を表示すると (管理ポータルなどで)、代わりに Male と Female が表示されます。各データ型クラスでは、LogicalToDisplay() などのメソッドが提供されます。
プロパティ・キーワードの指定
プロパティ定義では、プロパティの使用法に作用するオプションのプロパティ・キーワードを含めることができます。以下のリストに、よく使用されているキーワードのいくつかを示します。
このクラスのインスタンスをディスクに格納する前に、プロパティの値を設定する必要があることを指定します。既定では、プロパティは Required ではありません。サブクラスで、必要に応じてオプションのプロパティをマークできますが、その逆は実行できません。
プロパティの初期値を指定します。既定では、プロパティは初期値を持ちません。サブクラスは InitialExpression キーワードの値を継承し、それをオーバーライドできます。指定する値は、有効な ObjectScript 式である必要があります。
プロパティをデータベースに格納しないことを指定します。既定では、プロパティは Transient ではありません。サブクラスは Transient キーワードの値を継承しますが、それをオーバーライドできません。
プロパティがプライベートであることを指定します。サブクラスは Private キーワードの値を継承しますが、それをオーバーライドできません。
既定では、プロパティはパブリックであり、どのような場所でもアクセスできます。プロパティは (Private キーワードを使用して) プライベートとしてマークできます。その場合、それらが属するオブジェクトのメソッドによってのみアクセスできます。
InterSystems IRIS では、プライベート・プロパティは常に、プロパティを定義したクラスのサブクラスに継承され、参照できます。
他のプログラミング言語では、これらを保護されたプロパティと呼ぶことがあります。
このプロパティには、メモリ内ストレージを割り当てないことを指定します。既定では、プロパティは Calculated ではありません。サブクラスは Calculated キーワードを継承しますが、それをオーバーライドできません。
プロパティが多次元であることを指定します。このプロパティは、以下の点で他のプロパティとは異なります。
-
関連付けられているメソッドがありません (後続のトピックを参照)。
-
オブジェクトを検証または保存するときに、無視されます。
-
アプリケーションにそれを明示的に保存するコードが含まれていない場合、ディスクに保存されません。
-
クライアント・テクノロジに公開することはできません。
-
SQL テーブルに格納できず、SQL テーブルでも公開されません。
多次元プロパティはあまり使用されませんが、オブジェクト状態情報を一時的に格納する場合に役立ちます。
データ型に基づくプロパティ
プロパティを定義し、そのタイプをデータ型クラスと指定する場合、このセクションで説明するように、そのプロパティを定義し、操作するための特別なオプションがあります。
データ型クラス
データ型クラスでは、プロパティの値に関する一連のルールを適用できます。
InterSystems IRIS には、%Library.StringOpens in a new tab、%Library.IntegerOpens in a new tab、%Library.NumericOpens in a new tab、%Library.DateOpens in a new tab など多くのデータ型クラスが用意されています。%Library パッケージのクラスの名前は省略可能なため、これらの多くを省略できます。例えば、%DateOpens in a new tab は %Library.DateOpens in a new tab の省略形です。
各データ型クラスには、以下の機能があります。
-
コンパイラ・キーワードの値を指定します。プロパティの場合、コンパイラ・キーワードは、以下のようなことを実行できます。
-
プロパティを必須にします。
-
プロパティの初期値を指定します。
-
プロパティを SQL、ODBC、および Java クライアントに投影する方法を制御します。
-
-
以下のような詳細に影響を与えるパラメータの値を指定します。
-
データ型の論理値の最大値と最小値
-
文字列の最大文字数と最小文字数
-
小数点以下の桁数
-
最大文字数を超えた場合に文字列を切り捨てるかどうか
-
表示形式
-
特別な XML または HTML 文字のエスケープ方法
-
ユーザ・インタフェースで使用するための論理値および表示値の列挙リスト
-
文字列が一致する必要があるパターン (InterSystems IRIS パターン・マッチング演算子を自動的に使用)
-
XML のインポートまたは XML へのエクスポートの際に UTC タイム・ゾーンを尊重するか、無視するか
-
-
これは、リテラル・データを、格納形式 (ディスク上)、論理形式 (メモリ内)、表示形式の間で変換するための一連のメソッドを提供します。
独自のデータ型クラスを追加できます。例えば、以下は %Library.StringOpens in a new tab のカスタム・サブクラスを示しています。
Class MyApp.MyType Extends %Library.String
{
/// The maximum number of characters the string can contain.
Parameter MAXLEN As INTEGER = 2000;
}
データ型クラスのパラメータのオーバーライド
プロパティを定義し、そのタイプをデータ型クラスと指定する場合、そのデータ型クラスで定義されるどのパラメータもオーバーライドできます。
例えば、%IntegerOpens in a new tab データ型クラスは、クラス・パラメータ (MAXVAL) を定義しますが、このパラメータに対して値を提供しません。これを、プロパティ定義で以下のようにオーバーライドできます。
Property MyInteger As %Integer(MAXVAL=10);
このプロパティの場合、許容最大値は 10 です。
(データ型クラスの検証メソッドはメソッド・ジェネレータであるため、これは内部で機能します。指定するパラメータ値は、コンパイラがそのクラスのコードを生成するときに使用されます。
同様に、タイプ %StringOpens in a new tab のすべてのプロパティに照合タイプがあります。これにより、値を並べる方法 (先頭の文字の大文字化が有効かどうかなど) が決まります。既定の照合タイプは、SQLUPPERです。
以下の別の例では、データ型クラスは、DISPLAYLIST および VALUELIST パラメータを定義します。これらを使用して、ユーザ・インタフェースに表示する選択肢と、それらに対応する内部値を指定できます。
Property Gender As %String(DISPLAYLIST = ",Female,Male", VALUELIST = ",F,M");
他のプロパティ・メソッドの使用法
プロパティには、自動的に関連付けられた多くのメソッドがあります。これらのメソッドは、データ型クラスによって生成され、ObjectScript からアクセスできます。
例えば、3 つのプロパティでクラス Person を定義する場合、以下のようになります。
Class MyApp.Person Extends %Persistent
{
Property Name As %String;
Property Age As %Integer;
Property DOB As %Date;
}
生成された各メソッドの名前は、プロパティ名に継承クラスからのメソッド名を連結した名前です。以下の例に示すように、生成されたこれらのメソッドに ObjectScript からアクセスできます。Python から同じ情報にアクセスするには、関連付けられているメソッドを継承クラスから直接呼び出します。例えば、%DateOpens in a new tab クラスに関連付けられている一部のメソッド、したがって DOB プロパティでは以下のようになります。
Set x = person.DOBIsValid(person.DOB)
Write person.DOBLogicalToDisplay(person.DOB)
x = iris.cls("%Date").IsValid(person.DOB)
print(iris.cls("%Date").LogicalToDisplay(person.DOB))
IsValid はプロパティ・クラスのメソッドで、LogicalToDisplay は %DateOpens in a new tab データ型クラスのメソッドです。
メソッド
インスタンス・メソッドとクラス・メソッド (他の言語では静的メソッドと呼ぶ) の 2 種類のメソッドがあります。
Method キーワードの指定
メソッド定義では、メソッドがどのように動作するかに作用するオプションのコンパイラ・キーワードを含めることができます。以下のリストに、よく使用されているメソッド・キーワードのいくつかを示します。
InterSystems IRIS では、メソッドを ObjectScript または Python で記述できます。メソッドの記述に使用する言語を指定するには、以下の構文を使用します。
Method MyMethod() [ Language = objectscript ]
{
// implementation details written in ObjectScript
}
Method MyMethod() [ Language = python ]
{
# implementation details written in Python
}
メソッドで Language キーワードを使用しない場合、コンパイラはメソッドが ObjectScript で記述されていると想定します。
前述の例のように、メソッドの言語はすべて小文字で記述する必要があります。
このキーワードはメソッドがプライベートであることを指定するもので、ObjectScript メソッドでのみ使用できます。サブクラスは Private キーワードの値を継承しますが、それをオーバーライドできません。
既定では、メソッドはパブリックであり、どのような場所でもアクセスできます。メソッドは (Private キーワードを使用して) プライベートとしてマークできます。その場合、
-
それらが属するクラスのメソッドによってのみアクセスできます。
-
インターシステムズ・クラス・リファレンスには記載されません。
ただし、これは継承され、このメソッドを定義するクラスのサブクラスで使用できます。
他の言語では、このようなメソッドを保護されたメソッドと呼ぶことがあります。
他のクラス・メンバの参照
メソッド内で、ここに示す構文を使用し、他のクラスのメンバを参照します。
-
パラメータを参照するには、以下のような式を使用します。
..#PARAMETERNAME
# technique 1 iris.cls("Package.Class")._GetParameter("PARAMETERNAME") # technique 2 objectinstance._GetParameter("PARAMETERNAME")
インターシステムズが提供するクラスでは、慣例ですべてのパラメータがすべて大文字で定義されていますが、作成するコードでは大文字にしなくてもかまいません。
-
別のインスタンス・メソッドを参照するには、以下のような式を使用します。
..methodname(arguments)
self.methodname(arguments)
この構文をクラス・メソッド内で使用して、インスタンス・メソッドを参照することはできません。
-
別のクラス・メソッドを参照するには、以下の構文を使用します。
..classmethodname(arguments)
# technique 1 iris.cls("Package.Class").classmethodname(arguments) # technique 2 iris.cls(__name__).classmethodname(arguments)
Python の self 構文を使用してクラス・メソッドにアクセスすることはできません。代わりに、__name__ プロパティを使用して、前述の例に示すように現在のクラスの名前を取得できます。
-
(インスタンス・メソッド内のみ) インスタンスのプロパティを参照するには、以下のような式を使用します。
..PropertyName
self.PropertyName
同様に、オブジェクト値プロパティのプロパティを参照するには、以下のような式を使用します。
..PropertyNameA.PropertyNameB
self.PropertyNameA.PropertyNameB
ObjectScript の例で使用されている構文は、ドット構文と呼ばれます。
また、オブジェクト値プロパティのインスタンス・メソッドまたはクラス・メソッドを呼び出すこともできます。以下に例を示します。
Do ..PropertyName.MyMethod()
self.PropertyName.MyMethod()
他のクラスのメソッドの参照
メソッド内で (またはルーチン内で)、ここに示す構文を使用し、他のクラスのメソッドを参照します。
-
クラス・メソッドを呼び出し、その返り値にアクセスするには、以下のような式を使用します。
##class(Package.Class).MethodName(arguments)
iris.cls("Package.Class").MethodName(arguments)
以下に例を示します。
Set x=##class(Util.Utils).GetToday()
x=iris.cls("Util.Utils").GetToday()
以下のように、戻り値にアクセスせずにクラス・メソッドを呼び出すこともできます。
Do ##class(Util.Utils).DumpValues()
iris.cls("Util.Utils").DumpValues()
Note:##class は、大文字と小文字を区別しません。
-
インスタンス・メソッドを呼び出すには、インスタンスを作成し、ObjectScript または Python で以下のような式を使用してそのメソッドを呼び出し、その戻り値にアクセスします。
instance.MethodName(arguments)
以下に例を示します。
Set x=instance.GetName()
x=instance.GetName()
以下のように呼び出すことで、戻り値にアクセスせずにインスタンス・メソッドを呼び出すこともできます。
Do instance.InsertItem("abc")
instance.InsertItem("abc")
返り値がないメソッドもあるので、自身の状況にあった構文を選択してください。
現在のインスタンスの参照
場合によっては、インスタンス・メソッド内で、そのインスタンスのプロパティまたはメソッドではなく、現在のインスタンス自体を参照することが必要になります。例えば、他のコードを呼び出すときに、現在のインスタンスを渡すことが必要な場合があります。
ObjectScript では、特殊変数 $THIS を使用して現在のインスタンスを参照します。Python では、変数 self を使用して現在のインスタンスを参照します。
以下に例を示します。
Set sc=header.ProcessService($this)
sc=header.ProcessService(self)
メソッド引数
メソッドは、コンマ区切りリストで位置を示す引数を取ります。引数ごとに、型および既定の値を指定できます。
例えば、以下は、3 つの引数を取るメソッドの定義の一部分です。これは、InterSystems IRIS クラス内の ObjectScript メソッドと Python メソッドの両方で有効な構文です。
Method Calculate(count As %Integer, name, state As %String = "CA") as %Numeric
{
// ...
}
引数のうち 2 つが明示的な型を持ち、1 つが既定の値を持っています。一般的に、各引数の型を明示的に指定することは良い方法です。
メソッドが Python で定義されていて、そのメソッドの引数に既定値が指定されている場合、その引数を引数リストの末尾に配置して、コンパイル・エラーを避ける必要があります。
引数のスキップ
メソッドに適切な既定値がある場合、メソッドを呼び出すときに引数をスキップできます。ObjectScript と Python にはそれぞれ、引数をスキップするための独自の構文があります。
ObjectScript で引数をスキップするには、引数の値を指定せずにコンマ構造を維持します。例えば、以下は有効です。
set myval=##class(mypackage.myclass).GetValue(,,,,,,4)
InterSystems IRIS クラスでは、Python メソッドのシグニチャで最初に必須の引数を記述し、その後に引数と既定値を記述する必要があります。
そのメソッドを呼び出す際に、引数をメソッドのシグニチャの順番で指定する必要があります。したがって、1 つの引数をスキップした場合、その後の引数もすべてスキップする必要があります。例えば、以下は有効です。
ClassMethod Skip(a1, a2 As %Integer = 2, a3 As %Integer = 3) [ Language = python ]
{
print(a1, a2, a3)
}
TESTNAMESPACE>do ##class(mypackage.myclass).Skip(1)
1 2 3
値または参照による変数渡し
メソッドを呼び出す場合、値または参照によって、そのメソッドに変数の値を渡すことができます。
通常、メソッドのシグニチャは、引数の参照渡しを意図しているかどうかを示します。以下に例を示します。
Method MyMethod(argument1, ByRef argument2, Output argument3)
ByRef キーワードは、参照によってこの引数を渡すことを示します。Output キーワードは、この引数を参照によって渡すことと、この引数に最初に指定した値がメソッドによってすべて無視されることを示します。
同様に、メソッドを定義するときに、メソッド・シグニチャで ByRef および Output キーワードを使用すると、そのメソッドの他のユーザに、それをどのように使用することを意図しているのかを知らせることができます。
ObjectScript で引数を参照渡しするには、そのメソッドを呼び出すときに変数名の前にピリオドを付けます。Python では、渡す値に対して iris.ref() を使用し、その参照に対してメソッドを呼び出します。これら両方を以下の例に示します。
Do MyMethod(arg1, .arg2, .arg3)
arg2=iris.ref("peanut butter")
arg3=iris.ref("jelly")
MyMethod(arg1,arg2,arg3)
ByRef および Output キーワードは、インターシステムズ・クラス・リファレンスの利用者全員に役立つ情報を提供します。これらのキーワードは、コードの動作には影響しません。メソッドの呼び出し方法に関する規則を適用するのは、メソッドの作成者の責任です。
可変の引数
引数の個数を変えることができるメソッドを定義できます。以下に例を示します。
ClassMethod MultiArg(Arg1... As %List) [ Language = objectscript ]
{
Set args = $GET(Arg1, 0)
Write "Invocation has ",
args,
" element",
$SELECT((args=1):"", 1:"s"), !
For i = 1 : 1 : args
{
Write "Argument[", i , "]: ", $GET(Arg1(i), "<NULL>"), !
}
}
ClassMethod MultiArg(Arg1... As %List) [ Language = Python ]
{
print("Invocation has", len(Arg1), "elements")
for i in range(len(Arg1)):
print("Argument[" + str(i+1) + "]: " + Arg1[i])
}
既定値の指定
ObjectScript または Python メソッドで引数の既定値を指定するには、以下の例に示す構文を使用します。
Method Test(flag As %Integer = 0)
{
//method details
}
メソッドが呼び出されるとき、引数が指定されていない場合は既定値を使用します (既定値が指定されている場合)。メソッドが Python で記述されている場合、既定値を持つ引数は、引数リストの末尾に定義する必要があります。
ObjectScript では、$GET 関数を使用して既定値を設定することもできます。以下に例を示します。
Method Test(flag As %Integer)
{
set flag=$GET(flag,0)
//method details
}
ただし、この方法ではシグニチャに影響しません。
メソッド・ジェネレータ
メソッド・ジェネレータは、クラスのコンパイル中にクラス・コンパイラによって呼び出されるプログラムです。この出力は、メソッドの実際の実行時実装です。メソッド・ジェネレータは強力なクラス継承の方法を提供し、クラスやプロパティ継承の必要性に応じてカスタマイズされた、高性能で特別なコードを生成します。InterSystems IRIS ライブラリ内で、メソッド・ジェネレータは、データ型やストレージ・クラスによって広範囲に使用されます。
クラス・クエリ
InterSystems IRIS クラスには、クラス・クエリを含めることができます。クラス・クエリは、クラスが使用できる SQL クエリを定義し、クエリのためのコンテナとして使用するクラスを指定します。以下に例を示します。
Query QueryName(Parameter As %String) As %SQLQuery
{
SELECT MyProperty, MyOtherProperty FROM MyClass
WHERE (MyProperty = "Hello" AND MyOtherProperty = :Parameter)
ORDER BY MyProperty
}
アプリケーションで使用するための事前に定義された検索を提供するために、クラス・クエリを定義します。例えば、名前などの複数のプロパティによってインスタンスを検索したり、パリからマドリッドまでのすべての航空便など、一連の特定の条件に適合するインスタンスのリストを提供したりできます。ここに示した例では、パラメータを使用します。これは、柔軟なクエリを提供するための一般的な方法です。クラス・クエリはどのクラス内でも定義できます。クラス・クエリは永続クラス内に含める必要はありません。
XData ブロック
XML は、多くの場合、構造化されたデータを表すための便利な方法であるため、InterSystems IRIS クラスには、どのようなニーズに対しても整形式 XML ドキュメントを含めることを可能にするメカニズムがあります。このためには、もう 1 つの種類のクラス・メンバである XData ブロックを含めます。
InterSystems IRIS は、特定の目的のために XData ブロックを使用します。場合によっては、これらをユーザ自身のアプリケーションに活用することができます。
-
InterSystems IRIS Web サービスおよび Web クライアントに対する WS-Policy サポート。"Web サービスおよび Web クライアントの作成" を参照してください。この場合、XData ブロックはセキュリティ・ポリシーを記述します。
-
Business Intelligence では、XData ブロックを使用してキューブ、サブジェクト領域、KPI、およびその他の要素を定義します。
詳細は、"XData ブロックの定義と使用" を参照してください。
クラス定義におけるマクロとインクルード・ファイル
InterSystems IRIS クラス定義では、ObjectScript メソッド内にマクロを定義し、それらのマクロをそのメソッド内で使用できます。ただし、多くの場合、それらをインクルード・ファイル内で定義し、それをクラス定義の先頭でインクルードできます。以下に例を示します。
Include (%assert, %callout, %occInclude, %occSAX)
/// Implements an interface to the XSLT Parser. XML contained in a file or binary
/// stream may be transformed
Class %XML.XSLT.Transformer Extends %RegisteredObject ...
その後、そのクラスの ObjectScript メソッドは、そのインクルード・ファイル、またはそれにインクルードされたインクルード・ファイルに定義されたマクロを参照できます。
マクロは継承されます。つまり、サブクラスは、そのスーパークラスと同じマクロすべてにアクセスできます。
InterSystems IRIS における継承規則
他のクラスベースの言語と同様に、複数のクラス定義を継承によって結合できます。InterSystems IRIS クラス定義は、複数の他のクラスを拡張 (または他のクラスから継承) できます。また、それらのクラスが他のクラスを拡張することもできます。
InterSystems IRIS クラスは、Python で定義されたクラス (つまり、.py ファイルに含まれるクラス定義) から継承することはできません (逆の場合も同様です)。
以下のサブセクションでは、InterSystems IRIS のクラスにおける継承の基本規則について説明します。
継承順序
InterSystems IRIS では、継承順序に次の規則を使用します。
-
既定では、特定の名前のクラス・メンバが複数のスーパークラスで定義されている場合、そのサブクラスはスーパークラス・リストの左端のクラスから定義を取ります。
-
クラス定義に Inheritance = right が含まれている場合、サブクラスはスーパークラス・リストの右端のクラスから定義を取ります。
これまでの使用法により、大部分の InterSystems IRIS クラスには、Inheritance = right が含まれています。
プライマリ・スーパークラス
他のクラスを拡張するクラスはすべて、1 つのプライマリ・スーパークラスを持っています。
クラスで使用される継承順序に関係なく、プライマリ・スーパークラスは、左から右に読む場合の最初のクラスです。
どのクラス・レベルのコンパイラ・キーワードについても、指定されたクラスは、そのプライマリ・スーパークラスで指定された値を使用します。
永続クラスの場合、プライマリ・スーパークラスは特に重要です。"クラスとエクステント" を参照してください。
最も適切なタイプのクラス
あるオブジェクトが複数のクラスのエクステント (いくつかのスーパークラスのエクステントなど) に属するインスタンスである場合でも、そのオブジェクトには必ず最も適切なタイプのクラス (MSTC) があります。オブジェクトがクラスのインスタンスであるが、そのクラスのどのサブクラスのインスタンスにもなっていない場合、そのクラスはそのオブジェクトの最も適切なタイプのクラスになります。
メソッドのオーバーライド
クラスは、その 1 つまたは複数のスーパークラスからメソッド (クラスおよびインスタンス・メソッドの両方) を継承し、それらはオーバーライドできます。その場合、自身のメソッド定義のシグニチャが、オーバーライドするメソッドのシグニチャと一致していることを確認する必要があります。サブクラス・メソッドの各引数は、スーパークラス・メソッドの引数と同じデータ型を使用するか、そのデータ型のサブクラスを使用する必要があります。ただし、サブクラスのメソッドで、そのスーパークラスに定義されていない追加の引数を指定することはできます。
メソッドのシグニチャが一致する限り、ObjectScript で記述されているメソッドを Python メソッドでオーバーライドすることも、その逆を行うこともできます。
サブクラスのメソッド内で、スーパークラス内のそれがオーバーライドしたメソッドを参照できます。ObjectScript でそれを行うには、##super() 構文を使用します。以下に例を示します。
//overrides method inherited from a superclass
Method MyMethod() [ Language = objectscript ]
{
//execute MyMethod as implemented in the superclass
do ##super()
//do more things....
}
##super は、大文字と小文字を区別しません。
関連項目
これらのトピックの詳細は、以下のリソースを参照してください。
-
"クラスの定義と使用" では、InterSystems IRIS でのクラスおよびクラス・メンバの定義方法について説明しています。
-
"クラス定義リファレンス" には、クラス定義で使用するコンパイラ・キーワードのリファレンス情報があります。
-
"インターシステムズ・クラス・リファレンス" には、InterSystems IRIS で提供されるすべての非内部クラスに関する詳細があります。