Javaプログラムに初期設定を外部から渡す方法として、プログラム起動時のコマンドラインオプション、設定ファイル、システムプロパティ、リソースバンドル、プリファレンスAPI(java.util.pref)辺りが候補に挙がります。
今回、PCからシリアル通信でセンサー機器と通信し、センサー機器の状態をGUIで表示するスタンドアロンプログラムを作成しています。プログラムの構造は、GUIに纏わる部分、シリアル通信に纏わる部分とを疎結合しています。ここで、疎結合ゆえにプログラムの初期設定をどのように渡すかを悩むこととなりました。
候補となる方法
コマンドライン引数
GUIはJavaFXで作成しています。JavaFXはコマンドラインを解析し、JavaFXのParametersクラスにキー・バリュー形式で保持する仕組みを持っています。しかし、このParametersクラスをシリアル通信部分に渡してしまうと、シリアル通信部分がJavaFXのライブラリへ依存してしまい、結合を疎にする観点では後退してしまいます。
設定ファイル
プログラムの起動時に所定のパスにあるProperties形式の設定ファイルを読み込み、これを参照する方法であれば、Java SEの標準API(java.util.Properties)への依存で済むので、疎結合をそれなりには保てます。しかし、設定ファイルから生成したPropertiesインスタンスをGUIの各所とシリアル通信の各所に持ち回す必要が生じます。
JavaFXでは、通常上位のApplication派生クラスからコントローラクラスへは直接参照を持たないので、プロパティを渡すためにコントローラーの参照を取得するコードをApplication派生クラスに追加し、またコントローラーにはプロパティを渡すメソッドを追加し、コントローラーからさらに各クラスに渡すといった持ちまわしが生じます。
シリアル通信においても、そのプロパティを各クラスに渡す持ちまわしが生じます。
この持ちまわしを避けるとしたら、プロパティをシングルトンで実装するといったプログラム全体のグローバル参照が発生します。
今回は小さなプログラムなので、1つのプロパティでもそう煩雑にはなりませんが、大きなプログラムになると、1つのプロパティに数百個以上のキー・バリュー定義が格納されることになり、あまり望ましい姿ではありません。
システムプロパティ
Java起動時のコマンドライン(JVMオプション)でシステムプロパティを定義することができます。
システムプロパティは、Java SE標準のAPI(java.lang.SystemクラスのgetPropertyメソッド)で取得できるので、疎結合の点で問題はなく、持ちまわしも不要ですが、多数の項目があるとJava起動時のコマンドラインが膨大となってしまいます。
リソースバンドル
Javaには、主に国際化対応の仕組みとしてロケールに応じて切り替える文字列等のリソースをプロパティファイルまたはクラスに切り出し、実行時にロケールに応じたファイルを読み込むリソースバンドルの仕組みがあります。このファイルに初期設定を書く方法がありますが、リソースファイルは通常JARファイルの中に収められるので、インストール後に設定を変更する場合、JARから取り出し修正したファイルを再度JARに戻すという手順が必要になり、これも好ましくありません。また、リソースバンドルは主にGUIの表示で使うので、シリアル通信などGUIから切り離した内容を記述するのは不適切と思われます。
プリファレンスAPI
Javaには、プリファレンスAPI(java.util.prefs)があり、ユーザー毎に異なる設定を保存・読み出して使用することと、ユーザー共通の設定を保存・読み出して使用することができます。
これはJava SE標準APIなのでシリアル通信からJavaFXへの依存はなくて済みます。
プリファレンスAPIを通して設定する内容は、Windows OSの場合はレジストリに格納され、UNIX系OSの場合はユーザー毎の設定はユーザーのホームディレクトリ下のファイルに、ユーザー共通の設定はシステムで一意の場所にファイルで置かれます。
レジストリやファイルは、プログラムをインストールして最初にプリファレンスを保存するまで生成されないので、インストール直後から初期設定を置くにはプリファレンスAPIを使って保存操作を最初にする必要があります。また、実行するユーザーの権限ではユーザー共通の設定を書き込むことができないことがあります(通常このケースが多いかと)。プリファレンス設定ツールが必要になるかもしれません。
結局どれにしよう?
用途によりトレードオフすることとなりそうです。