ソフトなリアルタイムのパフォーマンス制約(場合によってはモンスターの脂肪クラス)を伴うR&D関連の作業の経験から、ORマッパーを使用しないことをお勧めします。このような状況では、「金属に触れる」ことを扱い、JDBC結果セットを直接操作する方がよいでしょう。これは、ソフトなリアルタイムの制約があり、パッケージごとに大量のデータ項目があるアプリに対する私の提案です。さらに重要なことに、永続化する必要のある個別のクラス(クラスインスタンスではなくクラス定義)の数が多く、仕様にメモリの制約がある場合は、HibernateのようなORMも避けたいと思うでしょう。
元の質問に戻ります。
あなたが抱えていると思われるのは、1)複数のデータ項目をOOモデルにマッピングすること、および2)そのような複数のデータ項目がグループ化または分離の良い方法を示さないことの典型的な問題です(そしてグループ化の試みは単に正しく感じられない傾向があります。 )ドメインモデルがそのような集約に適さない場合があり、そうするための人工的な方法を考え出すことは、通常、すべての設計要件と要望を満たさない妥協に終わります。
さらに悪いことに、OOモデルでは通常、すべてのアイテムがクラスのフィールドとしてクラスに存在する必要があります。このようなクラスは通常、動作がないため、-のようstruct
な構造、別名data envelope
またはdata shuttle
です。
しかし、そのような状況では、次の質問があります。
アプリケーションは、常に40、50以上のデータ項目すべてを一度に読み取り/書き込みする必要がありますか?
*すべてのデータ項目が常に存在する必要がありますか?*
問題のドメインの詳細はわかりませんが、一般的に、すべてのデータ項目を一度に処理する必要はほとんどないことがわかりました。これは、テーブルからすべての行を一度にクエリする必要がないため、リレーショナルモデルが優れているところです。問題のテーブル/ビューの投影として必要なものだけをプルします。
潜在的に多数のデータ項目があるが、平均してネットワークに渡されるデータ項目の数が最大数より少ない状況では、プロパティパターンを使用する方がよいでしょう。
すべてのアイテムを保持するモンスターエンベロープクラスを定義する代わりに:
// java pseudocode
class envelope
{
field1, field2, field3... field_n;
...
setFields(m1,m2,m3,...m_n){field1=m1; .... };
...
}
辞書を定義します(たとえば、マップに基づいて):
// java pseudocode
public enum EnvelopeField {field1, field2, field3,... field_n);
interface Envelope //package visible
{
// typical map-based read fields.
Object get(EnvelopeField field);
boolean isEmpty();
// new methods similar to existing ones in java.lang.Map, but
// more semantically aligned with envelopes and fields.
Iterator<EnvelopeField> fields();
boolean hasField(EnvelopeField field);
}
// a "marker" interface
// code that only needs to read envelopes must operate on
// these interfaces.
public interface ReadOnlyEnvelope extends Envelope {}
// the read-write version of envelope, notice that
// it inherits from Envelope, but not from ReadOnlyEnvelope.
// this is done to make it difficult (but not impossible
// unfortunately) to "cast-up" a read only envelope into a
// mutable one.
public interface MutableEnvelope extends Envelope
{
Object put(EnvelopeField field);
// to "cast-down" or "narrow" into a read only version type that
// cannot directly be "cast-up" back into a mutable.
ReadOnlyEnvelope readOnly();
}
// the standard interface for map-based envelopes.
public interface MapBasedEnvelope extends
Map<EnvelopeField,java.lang.Object>
MutableEnvelope
{
}
// package visible, not public
class EnvelopeImpl extends HashMap<EnvelopeField,java.lang.Object>
implements MapBasedEnvelope, ReadOnlyEnvelope
{
// get, put, isEmpty are automatically inherited from HashMap
...
public Iterator<EnvelopeField> fields(){ return this.keySet().iterator(); }
public boolean hasField(EnvelopeField field){ return this.containsKey(field); }
// the typecast is redundant, but it makes the intention obvious in code.
public ReadOnlyEnvelope readOnly(){ return (ReadOnlyEnvelope)this; }
}
public class final EnvelopeFactory
{
static public MapBasedEnvelope new(){ return new EnvelopeImpl(); }
}
read-only
内部フラグを設定する必要はありません。必要なのは、エンベロープインスタンスをインスタンスとしてダウンキャストするEnvelope
ことだけです(ゲッターのみを提供します)。
読み取りを期待するコードは読み取り専用エンベロープで動作する必要があり、フィールドの変更を期待するコードは可変エンベロープで動作する必要があります。実際のインスタンスの作成は、工場で区分化されます。
つまり、コンパイラを使用して、コード規則、どのインターフェイスをどこでどのように使用するかを管理するルールを確立することにより、読み取り専用にする(または変更可能にする)ようにします。
読み取るだけでよいコードとは別に、書く必要があるセクションにコードを階層化できます。それが完了すると、単純なコードレビュー(またはgrep)で、間違ったインターフェイスを使用しているコードを特定できます。)
問題:
非公開の親インターフェース:
Envelope
誤った/悪意のあるコードが読み取り専用エンベロープをベースエンベロープにキャストしてから可変エンベロープに戻すことを防ぐために、パブリックインターフェイスとして宣言されていません。意図されたフローは、可変から読み取り専用です-双方向であることを意図していません。
ここでの問題は、の拡張子がEnvelope
それを含むパッケージに制限されていることです。それが問題であるかどうかは、特定のドメインと使用目的によって異なります。
工場:
問題は、工場が非常に複雑になる可能性がある(そしておそらくそうなる)ということです。繰り返しますが、獣の性質。
検証:
このアプローチで発生するもう1つの問題は、フィールドXが存在することを期待するコードについて心配する必要があることです。元のモンスターエンベロープクラスがあると、少なくとも構文的にはすべてのフィールドが存在するため、その心配から部分的に解放されます...
...フィールドが設定されているかどうかにかかわらず、それは私が提案しているこの新しいモデルにまだ残っている別の問題でした。
したがって、フィールドXが表示されることを期待するクライアントコードがある場合、フィールドが存在しない場合(または、コンピューターに、または何らかの方法で適切なデフォルトを読み取る場合)、クライアントコードは何らかの種類の例外をスローする必要があります。
フィールドプレゼンスのパターンを特定します。フィールドXが存在することを期待するクライアントは、他のフィールドが存在することを期待するクライアントとは別にグループ化(階層化)される場合があります。
一部のルール(プログラムで、インタープリター、またはルールエンジンで提供されるルール)に従って、例外をスローするか、欠落しているフィールドのデフォルト値を計算するカスタムバリデーター(読み取り専用エンベロープインターフェイスへのプロキシ)を関連付けます。
タイピングの欠如:
これは議論の余地があるかもしれませんが、静的型付けで作業していた人々は、大まかに型付けされたマップベースのアプローチに行くことによって静的型付けの利点を失うことに不安を感じるかもしれません。これに対する反論は、ほとんどのWebは、Java側(JSTL、EL)でも、緩い型付けアプローチで機能するというものです。
問題はさておき、可能なフィールドの最大数が多く、常に存在するフィールドの平均数が少ないほど、このアプローチが最も効果的なパフォーマンスになります。コードがさらに複雑になりますが、それが獣の性質です。
その複雑さは解消されず、クラスモデルまたは検証コードのいずれかに存在します。ただし、特に大量の個別データ転送が予想される場合は、シリアル化とネットワークへの転送の方がはるかに効率的です。
それが役に立てば幸い。