1


他のエンティティと 1 対 1 および/または 1 対多の関係を持つエンティティ クラスがいくつかあります。

私のケースを反映した非常に一般的な例を作成しようとしています...次のテーブルがDBに保存されているとしましょう(null値は許可されていません):

   operations (ID, workerID, customerID, etc_etc)
      workers (ID, email, password, etc_etc)
    customers (ID, etc_etc)
 mobilePhones (workerID, phoneNumber)

次のことは明らかです。

  • 1 つの操作には1人の作業員と1人の顧客しか いません。
  • 1人の顧客が少なくとも 1 つの携帯電話番号を持っています。

したがって、次のエンティティ クラスがあります。

public class Customer {
    private int id;
    //other fields, then constructors, getters and setters
}

public class Worker {
    private int id;
    //other fields
    private String[] mobilePhones;
}

タイトルにも書きましたが、HibernateなどのORMが使えないので、DAOを使います。
{編集: ORM を使用できない理由を知りたがっていることを知っておくべきでした...まあ、ここのコメントに書いたように:これは課題です (ソフトウェア エンジニアリング試験のプロジェクト) . }

これで、が実際の作業者の IDに等しいすべての電話番号WorkerDAOから選択することで、1 対多の関係を簡単に管理できる で問題が発生することはないと思います。mobilePhonesworkerID

私にとっての本当の問題は、Operationとその仲間Workerとの間の関係をどのように管理するかということCustomerです。メモリの無駄を避けたい場合、Operationエンティティを次のように設計する必要があります。

public class Operation { // here I have some doubts
    private int id;
    private int workerId;
    private int customerId;
    //other fields
}

または多分このように:

public class Operation { // here I have some doubts
    private int id;
    private Worker worker;
    private Customer customer;
    //other fields
}

?

後者はよりオブジェクト指向のように見えますが、些細な意味が 1 つあります。クライアントがそれらを必要としない場合でも、worker と customer のインスタンスはメモリ内にOperation存在する必要があります。

さらに悪いことに、 OperationDAOworker と customer を新しい Worker および Customer インスタンスとして設定すると、同じ worker/customer を参照する複数のインスタンスがメモリに保持されます(たとえば、同じ worker によって実行される 2 つの操作)。メモリの浪費に加えて、これは間違いなくデータの不整合につながる可能性があります(たとえば、1 つのインスタンスが他のインスタンスを更新せずに変更されるなど)。

これを回避するには、現在どのインスタンスがロードされているかを認識できるクラスを導入する必要があります (たとえばList<Worker>List<Customer>、 などを使用)...正直なところ、これはやり過ぎのように思えます。

また、最初のリクエストでのみワーカーインスタンスを設定するなど、ある種の遅延フェッチを実装しようとすることもできると思いましたが、それでもメモリ内にあるものとクエリする必要があるものを追跡するクラスが必要です。このクラスがデータ アクセス ロジックに関連しているのか、ビジネス ロジックに関連しているのかさえわかりません(前者だと思いますが、まだわかりません)。

とにかく、私はキャッシングシステムを必要としないので、これをすべて実装する理由はまったくありません (そして、私はそれがそのように見えるように感じます)。

なにか提案を?

4

4 に答える 4

1

フレームワークは使用できませんが、フレームワーク自体が使用するパターンを使用できます。したがって、EAAの P に基づくこれらのソリューションをお勧めします。マーティン・ファウラー

  1. 最初のオプション(workerId フィールドと customerId フィールドを持つ操作)を使用し、すべてのエンティティ (操作、ワーカー、顧客) に対して行データ ゲートウェイを使用できます。ここで、メモリが問題であり、モデルでメモリが必要な場合は、Worker および Customer がロードされたすべてのインスタンスをIdentity Mapで制御し、リロードを回避します。

  2. 2 番目のオプション(ワーカーと顧客のインスタンスを稼働させる)を使用し、Lazy Loadを備えたTable Data Gatewayを使用して、必要な場合にのみインスタンスを読み込むことができます。

複数のインスタンスをロードするかどうかは、構築しているアプリケーションのタイプとインスタンスの範囲によって異なります。たとえば、CRUD ベースのアプリケーションを作成している場合、通常、インスタンスにはリクエスト スコープがあるため、2 番目のアプローチを使用し、メモリの浪費やデータの不整合について心配する必要はありません。

アドバイス: インターフェースを使用してタイプを定義してください。

于 2012-08-22T14:16:24.783 に答える
0

通常私は好む

public class Operation { 
    private int id;
    private Worker worker;
    private Customer customer;
    //other fields
}

これはよりオブジェクト指向であり、フェッチを容易にするためです。しかし、あなたは特にORMから離れているので(理由はわかりません???)、

public class Operation { 
    private int id;
    private int workerId;
    private int customerId;
    //other fields
}

より良い選択であり、必要なときにいつでもオブジェクトをロードできます。

ORMが最初の選択肢だったでしょう...:)

于 2012-08-21T17:27:48.893 に答える
0

自分に言い聞かせています(笑)。

davidmontoyago の回答のコメントで説明した問題を参照して、目標を達成するための最も簡単な方法は次のようになると考えました。

  • DB からロードされ、メモリ内にあるインスタンスを追跡するクラスを持つ。これはおそらく一種のユーティリティ クラスである可能性があります。つまり、プライベート コンストラクターとすべての静的メソッドです。
  • エンティティ クラスのインスタンスを返すすべての DAO が、要求されたインスタンスがキャッシュにあるかどうかを確認します。そうでない場合は、DB からロードしてキャッシュに追加します。

私はいくつかのコードをスケッチしようとします:

/* The class that will cache istances. */
static final class Cache { // package-private, so that only DAOs can see it.
    private static final int CAPACITY = 100; // max 100 istance per entity

    /* I will track each instance by its id, that is an Integer */
    private static Map<Integer,Worker> workers;
    private static Map<Integer,Customer> customers;
    private static Map<Integer,Operation> operations;

    private Cache() {} // I don't really need to istantiate this class

    // SOME OPERATIONS

    public static boolean isCached(Worker w);
    public static boolean isCached(Customer c);
    public static boolean isCached(Operation o);

    public static Worker getWorker(int id);
    public static Worker getCustomer(int id);
    public static Worker getOperation(int id);

    public static void addWorker(Worker w);
    public static void addCustomer(Customer c);
    public static void addOperation(Operation o);

}

class DAOWorkerImpl implements DAOWorker {
    public find(int id) {
        Worker w = null;
        if (Cache.isCached(id))
            w = Cache.getWorker(id);
        else {
            //retrieve worker
            Cache.addWorker(w);
        }
        return w;
    }
}

あなたはそれについてどう思いますか?それは非常に単純に見え、その仕事をするべきです。

Cacheところで、このコードを書いているときに、クラスを書くのを避けて、それぞれの DAO ですべてを管理できるようにしたほうがよいのではないかと考えました (例:DAOWorkerのメモリ内のインスタンスを管理するWorkerなど)。

私を納得させない唯一のことは、おそらくこれは単一責任の原則を破るだろうということです...それについてどう思いますか?

于 2012-08-23T12:45:43.580 に答える