マルチアプリケーション環境でのenumの処理

私たちの会社は主にJavaで開発され、共有された参照データと列挙型に依存するいくつかの「ライブ」システム(主に長時間実行されるサーバープロセス)をサポートしています。時々列挙型定義が新しい値を含むように展開されます。この場合、アプリケーションがそれぞれすべてのライブラリjarを含むプライベート "lib"フォルダを持っているという理由で、現在はすべてのアプリケーションを再配備します。 "enum entity"ライブラリを含む)。明らかにこれは望ましくないので、私は他の人々の勧告やアプローチを聞くことに興味があるでしょう。

私が考えたアイデア:

  1. 各アプリケーションの起動スクリプトを変更して、最新の "enum entity"ライブラリのバージョンを取得し、jarファイルをclasspathの前に追加します。
  2. 実行時に新しい列挙型定義を動的にクラス分けするためのある種のメカニズム。

これらのアプローチの問題点は、アプリケーションでは通常、次の形式のコードがあることです。

switch(enumVal) {
  case A:
   //Do something.
    break;
  case B:
   //Do something.
    break;
  default:
    throw new IllegalArgumentException("Invalid enum value: " + enumVal);
}

...そして、彼らがデフォルトのケースに当たったときに失敗し始めるでしょう。おそらくこれは、これらのエンティティが列挙型であってはならないことを示唆しています。私たちの場合は本当に便利なトレードオフです。あるいは、単にアプリケーションが脆弱であり、デフォルトのケースをより上手く処理する必要があることを示唆するだけのものかもしれません。

3
私はあなたのアプリデザインを考え直さなければならないと思う。覚えておいてください。
追加された 著者 Mister Smith,
列挙型はコンパイル時定数です。したがって、再起動するだけでは不十分です。列挙型で何かを変更する場合は、それらを使用するすべてのクラスを再コンパイルする必要があります。
追加された 著者 ssedano,
@Udo Fholl:Javaは実行時と名前だけで(遅い)バインディングを実行するので、あまり真実ではありません。新しい要素だけがどんなクラスファイル(目に見えるインタフェース)にも追加された場合、既存のコードを再コンパイルする必要はありません。
追加された 著者 JimmyB,
列挙型の定義が拡大されると、すべてのアプリが新しい値をすぐに使用し始めますか?これらの列挙型を何のために使用していますか?列挙型に新しい値を追加するが、アプリケーションコード内のどこにも参照しない場合、アプリケーションによって(valueOf()を使用するなどして)まだ使用されていますか?
追加された 著者 socha23,

2 答え

オブジェクト指向は、この問題を解決するために特別に考案されました。あなたのスイッチは、暗黙的なものがはるかに優れていたとしても、実際には明示的な仮想テーブルに過ぎません。列挙型の代わりにインタフェース/基本クラスを使用するようにアプリケーションを再設計することを検討する必要があります。

これにより、オブジェクトの作成時間に問題が移動し、各列挙の単一の変更ポイントがすぐに利用できます。また、プラグインベースのアーキテクチャーの導入の道を開きます。これは、再コンパイルを必要とせず、アプリケーションを再起動せずにアプリケーションを拡張する可能性もあります。長年実行されているサーバー・プロセスについて言えば、ダウンタイムの削減は魅力的です。

再コンパイルを避ける最も簡単な方法は、おそらく依存性注入を採用することです。 Spring のようなフレームワークを使用すると、作成する必要のあるオブジェクトを指定して、名前でロードできる1つ以上の構成ファイルがあります。

1
追加された
私はいくつかのより多くの情報で私の答えを更新します
追加された 著者 Nicola Musatti,
はい、フォルダファイルまたはjarファイルにクラスファイルを追加することはできますが、後者はおそらく「ホット」追加を防ぐことになります。私は設定を自動的にアップグレードする方法の詳細に精通していません。自分で行う必要はないからです。
追加された 著者 Nicola Musatti,
それは面白い。彼は適切なオブジェクト指向設計を持っていたとしましょう。ある日、新しい要件が導入され、新しいクラス(少なくとも)を追加する必要があります。再コンパイルせずにシステムに入れるのはどのような選択肢ですか?
追加された 著者 Mister Smith,
さて、コード化されたファクトリの代わりに、XMLがあります。しかし、再び、DIフレームワークがインスタンス化するためのシステムに新しいクラスを導入する必要がありますか?どのように再コンパイルせずに?いくつかのフォルダにクラスファイルを追加するだけですか?もう1つの質問:DIフレームワークでXMLが変更されたことが検出されるか、再起動が必要ですか?
追加された 著者 Mister Smith,

スミスさんはそうです。列挙型や古い列挙型の定数を拡張することはほとんどできませんが、通常は良いアプローチではありません。
あなたが暗示するように、新しい列挙値には、それを使用するクライアントによる特殊な動作/処理が必要です。列挙を変更すると、クライアントも変更する必要があります。これは本当に悪いことです。実際に別の方法で再設計しようとしています。

1
追加された
はい、しかし列挙型でもメソッドを持つことができます。あなたは単一レベルの継承階層に悩まされていますが、通常のクラスとほとんど同じ挙動を持つことができます。列挙定数メソッドごとに異なるオーバーライドを設定することもできます。したがって、そのswitchまたはif-elseをコーディングする代わりに、各enum/classメソッドの内部で処理されるものを移動し、クライアントコードから呼び出します。
追加された 著者 Mister Smith,
列挙型定数は、列挙型「クラス」のサブクラスの一種です。列挙型で定義されたメソッドを特定の列挙型定数でオーバーライドするには、定数の特定のクラス本体を持つことができます。私がクリーンなデザインと呼んでいるのではなく、機能します。
追加された 著者 Mister Smith,
私はもう一度同意し、追加することができます:すべてのクライアントで同じであるように、enums自体の単一の場所に特殊な動作/処理を実装する最初にクライアントに実装する必要はありません 。
追加された 著者 JimmyB,
ああ、列挙型は継承をサポートしていないため、多形性はサポートされていないことに注意してください。
追加された 著者 JimmyB,
そうですが、クライアントは、動作を変更するために提供された列挙型の独自の実装を派生することはできません。
追加された 著者 JimmyB,