4D 20 R5は、開発者のための強力な機能を提供します:シングルトンです!
シングルトンデザインパターンは、アプリケーション全体でアクセス可能なクラスのインスタンスを1つ作成します。
このパターンには、以下のような多くの利点があります:
- プロセス間の値のホスト
- ユーティリティ・クラス
- ファクトリーデザインパターンのベース
- など多くの利点があります。
この新しいコンセプトの詳細については、このまま読み進めてください!
4Dには2種類のシングルトンがあります:プロセスごとにユニークなシングルトンと、アプリケーション全体でユニークな共有シングルトンです。シングルトンは標準オブジェクトで、共有シングルトンは共有オブジェクトです。
シングルトンを定義するのは非常に簡単で、クラスのコンストラクタにシングルトンキーワードを追加するだけです:
singleton Class constructor()
共有シングルトンの定義も非常に簡単で、共有クラスでsingletonキーワードを使うだけです:
shared singleton Class constructor()
その瞬間から、me属性を通してシングルトンに簡単にアクセスできるようになる:
$singleton:=cs.SingletonClass.me
me属性はシングルトンインスタンス(他の言語ではgetInstance()関数でアクセスすることが多い)です。シングルトンに初めてアクセスするときにインスタンス化されます。
例
シングルトンはとても便利なので、これからたくさん使うことになるでしょう。長い説明よりもシングルトンの例をお望みだと思いますので、いくつか用意しました。
ユーティリティ・クラス
簡単な例から始めましょう:ユーティリティクラスです。ユーティリティクラスは、アプリケーションのいたるところで使われる多くのユーティリティ関数をホストしています。これらの関数を1つのクラスにまとめると、すべてのユーティリティ関数を見つけるのがとても簡単で、メソッドが散らかることもないので、コードのメンテナンスに役立ちます。
//Class UtilityClass
singleton Class constructor()
Function utilityFunction1()
Function utilityFunction2()
...
この瞬間から、この行でユーティリティ関数を呼び出すことができます:
cs.UtilityClass.me.utilityFunction1()
Websocket サーバー・ラッパー
シングルトンのもうひとつの典型的な使い方は、アプリケーションのどこでもアクセスできるオブジェクトのラッパーを作ることです。このクラスを考えてみよう:
//WebSocketServerWrapper
singleton Class constructor()
$handler:=cs.myWebsocketServerHandler.new()
This.webSocketServer:=4D.WebSocketServer.new($handler; {dataType: “object”})
Function terminate()
This.webSocketServer.terminate()
この瞬間から、次の呼び出しによってウェブサーバーを開始することができます:
CALL WORKER(“WebSocketServerWorker”; Formula(cs.WebSocketServerWrapper.me))
を呼び出すことでウェブサーバーを起動し、
CALL WORKER(“WebSocketServerWorker”; Formula(cs.WebSocketServerWrapper.me.terminate()))
ファクトリー
3つ目の例は、ファクトリーというデザインパターンを実装しています。ファクトリーはオブジェクトの新しいインスタンスを生成します。この場合、VehicleFactoryからVehicleオブジェクトを生成します:
//Class VehicleFactory
property vehicleBuilt:=0 //Number of vehicles built by the factory
shared singleton Class constructor()
shared Function buildVehicle($type : Text)->$vehicle : cs.Vehicle
Case of
: $type="car"
$vehicle:=cs.Car.new()
: $type="truck"
$vehicle:=cs.Truck.new()
: $type="sport car"
$vehicle:=cs.SportCar.new()
: $type="motorbike"
$vehicle:=cs.Motorbike.new()
Else
$vehicle:=cs.Car.new()
End case
This.vehicleBuilt+=1
シングルトンであるおかげで、このVehicleFactoryを呼び出すことで、1行でプロセス(または共有アプリケーション)のどこからでも新しいVehicleを取得することができます:
$vehicle:=cs.VehicleFactory.me.buildVehicle("truck")
その場合、このファクトリーは新しい車両を返す前にビルドされた車両の数をカウントする以外には何もしません。
VehicleFactoryをアプリケーション全体で一意にしたい場合は、sharedキーワードを追加する必要があります。関数buildVehicleは(This.vehicleBuiltをインクリメントすることで)VehicleFactoryを変更するので、関数の呼び出しと終了時にuseとend useが自動的に呼び出されるように、sharedキーワードも追加する必要があります。
プロセス間値
シングルトンのもう1つの古典的な使用法は、アプリケーション全体で使用するプロセス間値をホストすることです。このようなシングルトンの例を示します:
//Class InterprocessSingleton
shared singleton Class constructor()
This.version:=2
This.buildNumber:=1056
ここから、例えばグローバル変数にとても簡単にアクセスできます:
cs.InterprocessSingleton.me.version
ヒント: アプリケーションの起動時にプロセス間値を初期化したい場合があります。通常はOn Application Startupメソッド内で初期化します:
//Class InterprocessSingleton
shared singleton Class constructor($file : 4D.File)
$json:=$file.getText()
$settingsJson:=JSON Parse($json)
This.version:=$settingsJson.version
This.buildNumber:=$settingsJson.buildNumber
この場合、versionとbuildNumberの値はJSONファイルから取得します。シングルトンの場合、new()関数を呼び出すことで、コンストラクタをパラメータ付きで呼び出す方法がある。例えば、我々の場合:
$myFile:=File("/RESOURCES/settings.json")
cs.InterprocessSingleton.new($myFile)
注意しなければならないのは、new()の呼び出しがシングルトンに初めてアクセスしたときであることです。シングルトンがアクセスされた後にnew()を呼び出すと、クラスのコンストラクタは呼び出されなくなります。
特別な感謝
シングルトンにアクセスするためにme属性を追加することを提案してくれたChris Belangerに感謝の意を表したい。
シングルトンが私たちにとってそうであるように、あなたにとってもエキサイティングなものであることを願っています。シングルトンについて質問があれば、4Dフォーラムで遠慮なく質問してほしい。