メインコンテンツまでスキップ
バージョン: 20 R6

クラス

概要

4D ランゲージでは クラス の概念がサポートされています。 プログラミング言語では、クラスを利用することによって、属性やメソッドなどを持つ特定のオブジェクト種を定義することができます。

ユーザークラスが定義されていれば、そのクラスのオブジェクトをコード内で インスタンス化 することができます。 各オブジェクトは、それ自身が属するクラスのインスタンスです。 クラスは、別のクラスを 継承 することで、その 関数 と、(宣言された および 計算された) プロパティを受け継ぐことができます。

4D におけるクラスモデルは JavaScript のクラスに類似しており、プロトタイプチェーンに基づきます。

たとえば、次のように Person クラスを定義した場合:

// クラス: Person.4dm
Class constructor($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname

Function get fullName() -> $fullName : Text
$fullName:=This.firstName+" "+This.lastName

Function sayHello() -> $welcome : Text

$welcome:="Hello "+This.fullName

この "Person" のインスタンスをメソッド内で作成するには、以下のように書けます:

var $person : cs.Person // Person クラスのオブジェクト
var $hello : Text
$person:=cs.Person.new("John";"Doe")
// $person:{firstName: "John"; lastName: "Doe"; fullName: "John Doe"}
$hello:=$person.sayHello() // "Hello John Doe"

クラスの管理

クラス定義

4D においてユーザークラスとは、/Project/Sources/Classes/ フォルダーに保存された専用の メソッド ファイル (.4dm) によって定義されます。 ファイル名がクラス名になります。

クラスを命名する際には、次のルールに留意してください:

  • クラス名プロパティ名の命名規則 に準拠している必要があります。
  • クラス名の大文字・小文字は区別されます。
  • 競合防止のため、データベースのテーブルと同じ名前のクラスを作成するのは推奨されないこと

たとえば、"Polygon" という名前のクラスを定義するには、次のファイルを作成する必要があります:

Project フォルダー Project Sources Classes Polygon.4dm

クラスの削除

既存のクラスを削除するには:

  • ディスク上で "Classes" フォルダーより .4dm クラスファイルを削除します。
  • 4D エクスプローラーでは、クラスを選択した状態で をクリックするか、コンテキストメニューより 移動ゴミ箱 を選択します。

4D インターフェースの使用

ファイル メニューまたはエクスプローラーなど、4D インターフェースを介してクラスを作成した場合には、クラスファイルは自動的に適切な場所に保存されます。

ファイルメニューとツールバー

4D 開発の ファイル メニューまたはツールバーより 新規 > クラス... を選択することで、開いているプロジェクトにクラスファイルを新規作成することができます。

Ctrl+Shift+Alt+k ショートカットも使用できます。

エクスプローラー

エクスプローラーの メソッド ページにおいて、クラスは クラス カテゴリに分類されています。

クラスを新規作成するには次の方法があります:

  • クラス カテゴリを選択し、 ボタンをクリックします。
  • エクスプローラーウィンドウの下部にあるアクションメニュー、またはクラスグループのコンテキストメニューから 新規クラス... を選択します。
  • エクスプローラーのホームページのコンテキストメニューより 新規 > クラス... を選択します。

クラスのコードサポート

各種 4Dウィンドウ (コードエディター、コンパイラー、デバッガー、ランタイムエクスプローラー) において、クラスコードは "特殊なプロジェクトメソッド" のように扱われます:

  • コードエディター:
    • クラスは実行できません
    • クラスメソッドはコードのブロックです
    • オブジェクトメンバーに対する 定義に移動 操作はクラスの Function 宣言を探します。例: "$o.f()" の場合、"Function f" を見つけます。
    • クラスのメソッド宣言に対する 参照箇所を検索 操作は、そのメソッドがオブジェクトメンバーとして使われている箇所を探します。例: "Function f" の場合 "$o.f()" を見つけます。
  • ランタイムエクスプローラーおよびデバッガーにおいて、クラスメソッドは <ClassName> コンストラクターまたは <ClassName>.<FunctionName> 形式で表示されます。

クラスストア

定義されたクラスには、クラスストアよりアクセスすることができます。 クラスストアには次の二つが存在します:

  • cs - ユーザークラスストア
  • 4D - ビルトインクラスストア

cs

cs : Object

引数説明
classStoreObject<-プロジェクトまたはコンポーネントのユーザークラスストア

cs コマンドは、カレントプロジェクトまたはコンポーネントのユーザークラスストアを返します。 これには、プロジェクトまたはコンポーネントにて 定義 されている、すべてのユーザークラスが含まれます。 デフォルトでは、 ORDAクラス のみ利用可能です。

例題

myClass オブジェクトの新規インスタンスを作成するには、次のように書きます:

$instance:=cs.myClass.new()

4D

4D : Object

引数説明
classStoreObject<-4Dクラスストア

4D コマンドは、ビルトイン 4Dクラスのクラスストアを返します。 CryptoKey などの専用 API へのアクセスを提供します。

例題

CryptoKey クラスに新規キーを作成するには、次のように書きます:

$key:=4D.CryptoKey.new(New object("type";"ECDSA";"curve";"prime256v1"))

Class オブジェクト

プロジェクトにおいてクラスが 定義 されていれば、それは 4Dランゲージ環境に読み込まれます。 クラスとは、それ自身が "Class" クラス のオブジェクトです。 Class オブジェクトは次のプロパティや関数を持ちます:

また、Class オブジェクトは constructor オブジェクトを参照することも可能です (任意)。

Class オブジェクトそのものは 共有オブジェクト です。 したがって、異なる 4Dプロセスから同時にアクセスすることができます。

継承

クラス宣言において Class extends キーワードを使うと、そのクラスは親クラス (つまり スーパークラス) を継承します。

関数やプロパティがクラス内で見つからない場合、4D はそのクラスの スーパークラス 内を検索します。 見つからない場合、4D はさらに、そのスーパークラスのスーパークラス内を探します。 これは、スーパークラスが存在しなくなるまで続きます (すべてのオブジェクトは "Object" スーパークラスを継承しています)。

クラスキーワード

クラス定義内では、専用の 4Dキーワードが使用できます:

  • Function <Name>: オブジェクトのクラス関数を定義します。
  • Class constructor: クラスの新規インスタンス (オブジェクト) を初期化します。
  • property: オブジェクトのスタティックプロパティを型定義します。
  • Function get <Name>Function set <Name>: オブジェクトの計算プロパティを定義します。
  • Class extends <ClassName>: 継承を定義します。

Function

シンタックス

{shared} Function <name>({$parameterName : type; ...}){->$parameterName : type}
// コード

There is no ending keyword for function code. The 4D language automatically detects the end of a function's code by the next Function keyword or the end of the class file.

クラス関数とは、当該クラスのプロパティです。 クラス関数は 4D.Function クラスのオブジェクトです。 クラス定義ファイルでは、Function キーワードに続けて関数名を指定して宣言をおこないます。

共有クラス 内で関数が宣言されている場合は、shared キーワードを使用することによって、Use...End use structure 構文なしで関数を呼び出せるようにできます。 詳細については、後述の 共有関数 の項目を参照ください。

関数名は プロパティ名の命名規則 に準拠している必要があります。

プロパティと関数は同じ名前空間を共有しているため、同じクラスのプロパティと関数に同じ名前を使用することは許されていません (この場合、エラーが発生します)。

tip

アンダースコア ("_") 文字で関数名を開始すると、その関数は 4Dコードエディターの自動補完機能から除外されます。 たとえば、MyClassFunction _myPrivateFunction を宣言した場合、コードエディターにおいて "cs.MyClass." とタイプしても、この関数は候補として提示されません 。

関数名のすぐ後に、名前とデータ型を指定して 引数 を宣言します (戻り値の宣言も可)。 例:

Function computeArea($width : Integer; $height : Integer)->$area : Integer

クラスメソッド内でオブジェクトインスタンスを参照するには This コマンドを使います。 例:

Function setFullname($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname

Function getFullname()->$fullname : Text
$fullname:=This.firstName+" "+Uppercase(This.lastName)

クラス関数の場合には、Current method name コマンドは次を返します: <ClassName>.<FunctionName> (例: "MyClass.myFunction")。

アプリケーションのコード内では、クラス関数はオブジェクトインスタンスのメンバーメソッドとして呼び出され、引数 を受け取ることができます。 以下のシンタックスがサポートされています:

  • () 演算子の使用。 例: myObject.methodName("hello")
  • "4D.Function" クラスメンバーメソッドの使用:
スレッドセーフに関する警告

クラス関数がスレッドセーフではないのに、"プリエンプティブプロセスで実行可能" なメソッドから呼び出された場合:

  • 普通のメソッドの場合とは異なり、コンパイラーはエラーを生成しません。
  • ランタイムにおいてのみ、4D はエラーを生成します。

引数

関数の引数は、引数名とデータ型をコロンで区切って宣言します。 パラメーター名は プロパティ名の命名規則 に準拠している必要があります。 複数のパラメーター (およびその型) を宣言する場合は、それらをセミコロン (;) で区切ります。

Function add($x; $y : Variant; $z : Integer; $xy : Object)

パラメーターの型が宣言されていない場合には、バリアント 型として定義されます。

戻り値

関数の戻り値を宣言するには (任意)、入力パラメーターリストに矢印 (->) と戻り値の定義を追加します。 例:

Function add($x : Variant; $y : Integer)->$result : Integer
$result:=$x+$y

コロン (:) 記号の後に戻り値のデータ型だけを指定し、そのうえで return 文 を使って戻り値を返すこともできます (これは関数の実行を終了します)。 例:

Function add($x : Variant; $y : Integer): Integer
// なんらかのコード
return $x+$y

例題 1

property name : Text
property height; width : Integer

// クラス: Rectangle
Class constructor($width : Integer; $height : Integer)
This.name:="Rectangle"
This.height:=$height
This.width:=$width

// 関数定義
Function getArea()->$result : Integer
$result:=(This.height)*(This.width)
// プロジェクトメソッドにて

var $rect : cs.Rectangle
var $area : Real

$rect:=cs.Rectangle.new(50;100)
$area:=$rect.getArea() //5000

例題 2

return 文 を使った例です:

Function getRectArea($width : Integer; $height : Integer) : Integer
If ($width > 0 && $height > 0)
return $width * $height
Else
return 0
End if

Class Constructor

シンタックス

// クラス: MyClass
{shared} {singleton} Class Constructor({$parameterName : type; ...})
// コード

There is no ending keyword for class constructor function code. The 4D language automatically detects the end of a function's code by the next Function keyword or the end of the class file.

クラスコンストラクター関数を使って、ユーザークラスのオブジェクトを生成・初期化することができます。 このコンストラクターは任意の 引数 を受け取ることができます。

クラスコンストラクターが定義されていると、new() 関数を呼び出したときに、当該コンストラクターが呼び出されます (コンストラクターで引数を指定している場合は new() 関数に渡します)。

コンストラクター関数は、1つのクラスに 1つしか存在できません (そうでない場合はエラーが返されます)。 Super キーワードを使用することで、コンストラクターはスーパークラス (親クラス) のコンストラクターを呼び出すことができます。

コンストラクター内でインスタンスのプロパティを作成し、型宣言することができます (例題参照)。 また、インスタンスプロパティの値が、コンストラクターに渡される引数に依存しない場合は、property キーワードを使用して定義することができます。

shared キーワードを使うと 共有クラス が作成されます。共有クラスは、共有オブジェクトのインスタンス化にのみ使われます。 詳細については、後述の 共有クラス の項目を参照ください。

singleton キーワードを使うと シングルトン が作成されます。シングルトンクラスは、クラスインスタンスを一つに限定する場合に使われます。 詳細については、後述の シングルトンクラス の項目を参照ください。

例題

// クラス: MyClass
// MyClass のクラスコンストラクター
Class constructor ($name : Text ; $age : Integer)
This.name:=$name
This.age:=$age
// プロジェクトメソッドにて
// オブジェクトをインスタンス化します
var $o : cs.MyClass
$o:=cs.MyClass.new("John";42)
// $o = {"name":"John";"age":42}

property

シンタックス

property <propertyName>{; <propertyName2>;...}{ : <propertyType>}

property キーワードを使用して、ユーザークラス内のプロパティを宣言することができます。 クラスプロパティには、名前と型があります。

クラスプロパティを宣言することで、コードエディターの自動補完機能とエラー検出機能を強化します。

プロパティは、new() 関数が呼び出されたときに、新規作成するオブジェクトについて宣言されますが、自動で追加されるわけではありません (値が割り当てられた場合にのみ追加されます)。

宣言と同時にプロパティを初期化 すると、そのプロパティは自動的にオブジェクトに追加されます。

プロパティ名は プロパティ名の命名規則 に準拠している必要があります。

プロパティと関数は同じ名前空間を共有しているため、同じクラスのプロパティと関数に同じ名前を使用することは許されていません (この場合、エラーが発生します)。

プロパティの型として、以下のものがサポートされています:

propertyType内容
Textテキスト値
Date日付値
Time時間値
Booleanブール値
Integer倍長整数値
Real実数値
Pointerポインター値
Pictureピクチャー値
BlobスカラーBLOB値
Collectionコレクション値
Variantバリアント値
Objectデフォルトクラス (4D.Object) のオブジェクト
4D.<className>4Dクラス名のオブジェクト
cs.<className>ユーザークラス名のオブジェクト
cs.<namespace>.<className><namespace> コンポーネントクラス名のオブジェクト

宣言時に型を省略すると、プロパティはバリアント型として作成されます。

info

property キーワードは、クラス関数内の Function および Class Constructor ブロック外でのみ使用できます。

宣言と同時にプロパティを初期化する

プロパティを宣言する際には、1つのステートメントでデータ型と初期値の両方を指定することができます。 シンタックスは次の通りです:

property <propertyName> { : <propertyType>} := <Propertyvalue>

このシンタックスを使用する場合、複数のプロパティを一度に宣言することはできません。

宣言の際には型を省略することができます。その場合、可能な限り型は推論されます。 例:

// クラス: MyClass

property name : Text := "Smith"
property age : Integer := 42

property birthDate := !1988-09-29! // 日付は推測されます
property fuzzy // バリアント

プロパティを宣言行で初期化していると、new() 関数によるインスタンス化の後、コンストラクターが呼び出される前にクラスオブジェクトにプロパティが追加されます。

もしクラスが他のクラスを 継承 する場合、親クラスのプロパティは子クラスのプロパティよりも先にインスタンス化されます。

宣言と同時に色かするプロパティが 共有クラス のオブジェクトまたはコレクションである場合、その値は自動的に共有された値に変換されます:

// 共有クラス内
property myCollection := ["something"]
// myCollection は共有コレクションとなり、
// 以下と同等です:
myCollection := New shared collection("something")

例題

// クラス: MyClass

property name : Text
property age : Integer
property color : Text := "Blue"

メソッド内で:

var $o : cs.MyClass
$o:=cs.MyClass.new() // $o:{"color" : "Blue"}
$o.name:="John" // $o:{"color" : "Blue"; "name" : "John"}
$o.age:="Smith" // シンタックスチェックでエラー

Function getFunction set

シンタックス

{shared} Function get <name>()->$result : type
// コード
{shared} Function set <name>($parameterName : type)
// コード

Function getFunction set は、クラスの 計算プロパティ を定義するアクセサーです。 計算プロパティとは、計算をマスクするデータ型を持つ命名プロパティです。 計算プロパティの値にアクセスすると、4D は対応するアクセサーのコードを実行します:

  • プロパティを読み取るときには Function get が実行されます。
  • プロパティに書き込むときには Function set が実行されます。

プロパティがアクセスされない場合は、コードも実行されません。

計算プロパティは、メモリ上に保持する必要のないデータを処理するために設計されています。 計算プロパティは通常、永続的なプロパティに基づいています。 たとえば、クラスオブジェクトの永続的なプロパティとして、税込価格消費税率 が含まれている場合、税抜価格 は計算プロパティで処理することができます。

クラス定義ファイルでは、計算プロパティの宣言には、Function get (ゲッター) と Function set (セッター) のキーワードを使い、その後にプロパティ名を記述します。 名称は プロパティ名の命名規則 に準拠している必要があります。

Function get はプロパティの型の値を返し、Function set はプロパティの型の引数を受け取ります。 どちらも、標準的な 関数の引数 のルールに準拠する必要があります。

両方の関数が定義されている場合、計算プロパティは read-write となります。 Function get のみが定義されている場合、計算プロパティは read-only です。 この場合、コードがプロパティを変更しようとするとエラーが返されます。 Function set のみが定義されている場合、4D はプロパティの読み取り時に undefined を返します。

共有クラス 内で関数が宣言されている場合は、shared キーワードを使用することによって、Use...End use 構文なしで関数を呼び出せるようにできます。 詳細については、後述の 共有関数 の項目を参照ください。

計算プロパティの型は、ゲッター$return の型宣言によって定義されます。 有効なプロパティタイプ であれば、いずれも使用可能です。

オブジェクトプロパティに undefined を代入すると、型を保持したまま値がクリアされます。 このためには、まず Function get を呼び出して値の型を取得し、次にその型の空の値で Function set を呼び出します。

例題 1

// クラス: Person.4dm
property firstName; lastName : Text

Class constructor($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname

Function get fullName() -> $fullName : Text
$fullName:=This.firstName+" "+This.lastName

Function set fullName( $fullName : Text )
$p:=Position(" "; $fullName)
This.firstName:=Substring($fullName; 1; $p-1)
This.lastName:=Substring($fullName; $p+1)
// プロジェクトメソッドにて
$fullName:=$person.fullName // Function get fullName() が呼び出されます
$person.fullName:="John Smith" // Function set fullName() が呼び出されます

例題 2

Function get fullAddress()->$result : Object

$result:=New object

$result.fullName:=This.fullName
$result.address:=This.address
$result.zipCode:=This.zipCode
$result.city:=This.city
$result.state:=This.state
$result.country:=This.country

Class extends <ClassName>

シンタックス

// Class: ChildClass
Class extends <ParentClass>

クラス宣言において Class extends キーワードを使うと、別のユーザークラスの子ユーザークラスを作成することができます。 この子クラスは、親クラスのすべての機能を継承します。

クラス継承は次のルールに沿っている必要があります:

  • ユーザークラスはビルトインクラスを継承できません (例外は 4D.Object および ORDAクラス で、すべてのユーザークラスにデフォルトで継承されます)。
  • ユーザークラスは、別のプロジェクトやコンポーネントのユーザークラスを継承できません。
  • ユーザークラスは、自身を継承することはできません。
  • 間接的にも、自身を継承することはできません (例: "a" extends "b" かつ "b" extends "a")。
  • 共有クラスでないユーザークラスを継承 (extend) して 共有クラス を定義することはできません。

コードエディターやインタープリターは、これらのルールが破られていても検知することはできません。コンパイラーおよび "シンタックスチェック" のみがエラーを生成します。

派生クラスは、Super コマンドを使って親クラスのコンストラクターを呼び出すことができます。

例題

Polygon クラスを継承した Square クラスを作成します。

// クラス: Square

// パス: Classes/Square.4dm

Class extends Polygon


Class constructor ($side : Integer)

// 親クラスのコンストラクターを呼び出します
// 長方形の高さ・幅パラメーターに正方形の一辺の長さを引数として渡します
Super($side;$side)
// 派生クラスにおいては、'This' を使用するより先に
// Super を呼び出しておく必要があります
This.name:="Square"



Function getArea() -> $area : Integer
$area:=This.height*This.width

Super

Super( ...param : any )
Super : Object

引数説明
paramany->親コンストラクターに受け渡す引数
戻り値Object<-親オブジェクト

Super キーワードによって、スーパークラス (親クラス) を呼び出すことができます。

Super は次の 2つの目的のために使います:

  1. コンストラクターコード 内において、Super はスーパークラスのコンストラクターを呼び出すコマンドです。 コンストラクター内で使用する際には、Super コマンドは単独で使用され、また This キーワードよりも先に使用される必要があります。
  • 継承ツリーにおいて、すべてのクラスコンストラクターが正しく呼び出されていない場合には、エラー -10748 が生成されます。 呼び出しが有効であることを確認するのは、開発者の役目となります。
  • スーパークラスがコンストラクトされるより先に、This コマンドを使った場合には、エラー -10743 が生成されます。
  • オブジェクトのスコープ外で Super を呼び出した場合、または、スーパークラスコンストラクターがすでに呼び出されたオブジェクトを対象に呼び出した場合には、エラー -10746 が生成されます。
// myClass コンストラクター
var $text1; $text2 : Text
Super($text1) // テキスト型引数をスーパークラスコンストラクターに渡します
This.param:=$text2 // 2番目の引数を使用します
  1. クラスメンバー関数 内において、Super はスーパークラスのプロトタイプを指し、スーパークラス階層のメンバーメソッドの呼び出しを可能にします。
Super.doSomething(42) // スーパークラスにて宣言されている
// "doSomething" メンバーメソッドを呼び出します

例題 1

クラスコンストレクター内で Super を使う例です。 RectangleSquare クラス の共通要素がコンストラクター内で重複しないよう、このコマンドを呼び出します。

// クラス: Rectangle
Class constructor($width : Integer; $height : Integer)
This.name:="Rectangle"
This.height:=$height
This.width:=$width


Function sayName()
ALERT("Hi, I am a "+This.name+".")

// 関数定義
Function getArea()
var $0 : Integer

$0:=(This.height)*(This.width)
// クラス: Square

Class extends Rectangle

Class constructor ($side : Integer)

// 親クラスのコンストラクターを呼び出します
// 長方形の高さ・幅パラメーターに正方形の一辺の長さを引数として渡します
Super($side;$side)
// 派生クラスにおいては、'This' を使用するより先に
// Super を呼び出しておく必要があります
This.name:="Square"

Function getArea()
C_LONGINT($0)
$0:=This.height*This.width

例題 2

クラスメンバーメソッド内で Super を使う例です。 メンバーメソッドを持つ Rectangle クラスを作成します:

// クラス: Rectangle

Function nbSides()
var $0 : Text
$0:="I have 4 sides"

Square クラスには、スーパークラスメソッドを呼び出すメンバーメソッドを定義します:

// クラス: Square

Class extends Rectangle

Function description()
var $0 : Text
$0:=Super.nbSides()+" which are all equal"

この場合、プロジェクトメソッド内には次のように書けます:

var $square : Object
var $message : Text
$square:=cs.Square.new()
$message:=$square.description() // "I have 4 sides which are all equal"

This

This : Object

引数説明
戻り値Object<-カレントオブジェクト

This キーワードは、現在処理中のオブジェクトへの参照を返します。

This の値は、呼ばれ方によって決まります。 This の値は実行時に代入により設定することはできません。また、呼び出されるたびに違う値となりえます。

オブジェクトのメンバーメソッドとして フォーミュラ が呼び出された場合、This はメソッドの呼び出し元であるオブジェクトを指します。 例:

$o:=New object("prop";42;"f";Formula(This.prop))
$val:=$o.f() //42

クラスコンストラクター 関数が new() 関数により使用された場合、その内部の This はインスタンス化される新規オブジェクトを指します。

// クラス: ob

Class Constructor

// This のプロパティを
// 代入によって作成します
This.a:=42
// 4Dメソッドにて 
$o:=cs.ob.new()
$val:=$o.a //42

コンストラクター内で Super キーワードを使ってスーパークラスのコンストラクターを呼び出す場合、必ず This より先にスーパークラスのコンストラクターを呼ぶ必要があることに留意してください。順番を違えるとエラーが生成されます。 こちらの 例題 を参照ください。

基本的に、This はメソッドの呼び出し元のオブジェクトを指します。

// クラス: ob

Function f()
$0:=This.a+This.b

この場合、プロジェクトメソッド内には次のように書けます:

$o:=cs.ob.new()
$o.a:=5
$o.b:=3
$val:=$o.f() //8

この例では、変数 $o に代入されたオブジェクトは f プロパティを持たないため、これをクラスより継承します。 f は $o のメソッドとして呼び出されるため、メソッド内の This は $o を指します。

クラスコマンド

4Dランゲージには、クラス機能を扱う複数のコマンドがあります。

OB Class

OB Class ( object ) -> Object | Null

OB Class は引数として渡したオブジェクトのクラスを返します。

OB Instance of

OB Instance of ( object ; class ) -> Boolean

objectclass、またはその子クラスに属していれば、OB Instance oftrue を返します。それ以外の場合は false を返します。

共有クラス

共有クラス を作成することができます。 共有クラスとは、クラスの new() 関数が呼び出されたときに、共有オブジェクト をインスタンス化するユーザークラスのことを指します。 共有クラスは共有オブジェクトしか作れません。

共有クラスは 共有関数 をサポートしています。共有関数は、Use...End use 構文なしで呼び出すことができます。

クラスが共有クラスかどうかは、Classオブジェクトの ..isSharedプロパティで確認できます。

info

共有クラスの作成

共有クラスを作成するには、Class Constructor の前に shared キーワードを追加します。 例:

// 共有クラス: Person
shared Class Constructor($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname

// myMethod メソッド
var $person := cs.Person.new("John"; "Smith")
OB Is shared($person) // true
cs.Person.isShared // true

共有関数

共有クラス内で定義された関数が、そのクラスのオブジェクトを変更する場合には、共有オブジェクトへのアクセスを保護するために、Use...End use 構文を呼び出す必要があります。 しかし、shared として関数を定義することで、実行時には内部的な Use...End use を自動でトリガーするようにし、コードを簡略化することができます。

共有クラス内で共有関数を作成するには、Function キーワードの前に shared キーワードを追加します。 例:

// 共有クラス Foo
shared Class Constructor()
This.variable:=1

shared Function Bar($value : Integer)
This.variable:=$value // use/end use の呼び出しは不要です

共有クラスでないユーザークラス内で関数定義時に shared キーワードを使っても無視されます。

シングルトンクラス

シングルトンクラス とは、インスタンスを一つのみ作成するユーザークラスです。 シングルトンに関する詳細については、シングルトンに関する Wikipedia のページ を参照ください。 シングルトンは、それがインスタンス化されたプロセスにおいて一意のインスタンスを持ち、共有 シングルトンは、そのマシン上のすべてのプロセスにおいて一意のインスタンスを持ちます。 アプリケーションやプロセス内のどこからでも利用可能な値を定義するのにシングルトンは便利です。

クラスのシングルトンは、初回の cs.<class>.me プロパティの呼び出し時にインスタンス化されます。 インスタンス化されたクラスのシングルトンはその後、me プロパティの使用により常に返されます。

シングルトンを引数付きでインスタンス化する必要がある場合には、new() 関数を呼び出すこともできます。 この場合、アプリケーションの起動時に実行されるコードでシングルトンをインスタンス化することが推奨されます。

クラスがシングルトンクラスかどうかは、Classオブジェクトの ..isSingletonプロパティで確認できます。

スコープ

シングルトンインスタンスのスコープは、それがインスタンス化されたプロセスで、共有 シングルトンの場合はそのマシン上のすべてのプロセスです。

シングルトンが作成された場所共有されていない場合のスコープ共有されている場合のスコープ
4D シングルユーザープロセスアプリケーション
4D Serverプロセス4D Server のマシン
4Dリモートモードプロセス (注意: シングルトンは "双子" プロセス間で同期されません)4Dリモートのマシン

インスタンス化されると、シングルトンクラス (およびそのシングルトン) は、マシン上で実行中のアプリケーション内に参照が存在する限り存在し続けます。

info

ORDAに基づいたデータモデルクラス では、シングルトンクラスはサポートされていません。

シングルトンの作成

シングルトンクラスを作成するには、Class Constructor の前に singleton キーワードを追加します。 例:

// クラス: ProcessTag
singleton Class Constructor()
This.tag:=Random

シングルトンを使うには:

// プロセス内で
var $mySingleton := cs.ProcessTag.me // 初回のインスタンス化
// 例: $mySingleton.tag = 5425
...
var $myOtherSingleton := cs.ProcessTag.me
// $myOtherSingleton.tag = 5425

// 別のプロセスで
var $mySingleton := cs.ProcessTag.me // 初回のインスタンス化
// 例: $mySingleton.tag = 14856
...
var $myOtherSingleton := cs.ProcessTag.me
// $myOtherSingleton.tag = 14856

共有シングルトンの作成

マシン上の全プロセスで共有されるシングルトンを作成するには、Class Constructor の前に shared singleton キーワードを追加します。 例:

// クラス: VehicleFactory

property vehicleBuilt : Integer

shared singleton Class constructor()
This.vehicleBuilt := 0 // 工場が完成させた車両の数

shared Function buildVehicle ($type : Text) -> $vehicle : cs.Vehicle

Case of
: $type="車"
$vehicle:=cs.Car.new()
: $type="トラック"
$vehicle:=cs.Truck.new()
: $type="スポーツカー"
$vehicle:=cs.SportCar.new()
: $type="オートバイ"
$vehicle:=cs.Motorbike.new()
Else
$vehicle:=cs.Car.new()
End case
This.vehicleBuilt+=1

すると、cs.VehicleFactory シングルトンを呼び出すことで、そのマシン上でアプリケーションのどこからでも 1行で新しい車両を取得することができます:

$vehicle:=cs.VehicleFactory.me.buildVehicle("トラック")

buildVehicle() 関数は (This.vehicleBuilt をインクリメントして) cs.VehicleFactory シングルトンを変更するので、shared キーワードを使う必要があります。

参照

詳細に関しては、このブログ記事 を参照ください。