私はクラスOrder
を持っているとしましょう。 Order
はOrder.finish()
メソッドを呼び出して終了することができます。 Order
が終了すると、内部的に、仕上げの日付が設定されている:ドメイン中心のアプリケーションにデータを格納する際のカプセル化をどのように尊重するのですか?
Order.java
public void finish() {
finishingDate = new Date();
}
をアプリケーションのビジネスロジックでは、Order
のfinishingDate
を公開する必要はありません、それはそうゲッターのないプライベートフィールドです。
Order
を終了した後、データベースで更新したいとします。例えば、私はupdate
方法とDAO有することができる:この方法では
OrderDao.java
public void update(Order order) {
//UPDATE FROM ORDERS SET ...
}
を、Iは、テーブルを更新するために、Order
の内部状態が必要フィールド。しかし、私はその前に、Order
のfinishingDate
フィールドを公開する必要はないと言っていました。
私はOrder.getFinishingDate()
メソッドを追加した場合:
- を私がビジネス価値を追加することなく、
Order
クラスの契約を変更しています、「技術的」な理由(データベース内UPDATE
) - ためUBT私は私は内部状態を公開しているので、オブジェクト指向プログラミングのカプセル化の原則に違反しています。
これをどのように解決しますか? ORMの「エンティティ」クラスのようなゲッターを追加することは受け入れられますか?
私は、クラス自体(実装)がそれ自身をいかにして持続するかを知っている別のアプローチを見てきました。このような何か(非常に単純な例で、それだけで問題のためです):
public interface Order {
void finish();
boolean isFinished();
}
public class DbOrder implements Order {
private final int id;
private final Database db;
//ctor. An implementation of Database is injected
@Override
public void finish() {
db.update("ORDERS", "FINISHING_DATE", new Date(), "ID=" + id);
}
@Override
public boolean isFinished() {
Date finishingDate = db.select("ORDERS", "FINISHING_DATE", "ID=" + id);
return finishingDate != null;
}
}
public interface Database {
void update(String table, String columnName, Object newValue, String whereClause);
void select(String table, String columnName, String whereClause);
}
別にパフォーマンスの問題(実際には、それがキャッシュされたか何かすることができます)から、私はこのアプローチを好むが、それは多くのことを模擬するために私たちを強制的にテスト時には、すべてのロジックが「メモリ内」ではないためです。つまり、テスト中のロジックを「実行」するために必要なデータはメモリ内のフィールドだけではなく、外部コンポーネント(この場合はDatabase
)によって提供されます。
をロバートに答えてくれてありがとう。 'persist()'メソッドが実際にビジネスの一部であることは私にとっては難しいことです。私が今投稿したアプローチについてどう思いますか?編集した質問を確認してください。もう一度ありがとうございます –
私はその考え方も好きですが、すべてのロジックがDBに委任されている場合にしか使用できませんが、常にそうであるとは限りません。しかし、オブジェクトがとにかくそれをいつ行うべきかを知っているならば、あなたは 'persist()'メソッドを持つ必要はありません。例えば、 'finish()'ロジックには現在の状態を自動的にデータベースに永続化することが含まれます。それはすべて正確な要件とセマンティクスに依存します。 –