29754


下記の質問に関連します。  
[特定のパッケージやjarに対してのみ公開する可視性設定は可能か？](https://ja.stackoverflow.com/questions/28771/%e7%89%b9%e5%ae%9a%e3%81%ae%e3%83%91%e3%83%83%e3%82%b1%e3%83%bc%e3%82%b8%e3%82%84jar%e3%81%ab%e5%af%be%e3%81%97%e3%81%a6%e3%81%ae%e3%81%bf%e5%85%ac%e9%96%8b%e3%81%99%e3%82%8b%e5%8f%af%e8%a6%96%e6%80%a7%e8%a8%ad%e5%ae%9a%e3%81%af%e5%8f%af%e8%83%bd%e3%81%8b)

DDDにおける集約は、その内部状態（集約に含まれるエンティティやEnum型フィールド等）は公開せず、ユースケース上必要となるメソッドのみを外部に公開します。  
しかし、永続化層ではその内部状態を調べてデータベースのテーブルにマッピングしなければなりません。  
永続化のために全ての内部状態を`public`メソッドで公開するのは避けたいので、何らかの制約のもとで内部状態を取得する仕組みを求めています。

目標とする隠蔽のレベルですが、最低限、「うっかり呼んでしまった」を防げれば良いと考えています。  
`public`メソッドになっていると、その集約オブジェクトの設計（どの`public`メソッドが“真の”`public`なのか）に関する知識が無ければ、「うっかり」呼んでしまいますが、何か特別な手続きを踏む必要性を取り入れれば、「うっかり」は防げます。

この条件下では、どのようなクラス設計が良いでしょうか。  
何か応用可能なデザインパターンなどありませんか？


CC BY-SA 3.0
2016-09-10T02:59:10.253
28793
2016-10-22T10:08:41.053
2017-04-13T12:52:38.920
-1
8078
question
java ドメイン駆動設計
集約を分解して永続化するための設計


クラス設計の問題ではなくって、一般的に java のコードに置いてどうやって spec (仕様) プロジェクトと impl
プロジェクトを分離・ビルドするべきなのか問題なのではないか、と考えています。

一般的に、 spec プロジェクトと impl プロジェクトを分離して、各 impl プロジェクトはその他の spec
プロジェクトにのみ依存するようにします。すると、 spec クラスのもののみがその他の場所から利用されます。そして、各 impl
クラスは別々にビルドします。C言語で言う所のヘッダとソースの関係が近いと思います。

実際に動作するもの (war とか) を作る時には、別々にビルドしていたこいつらをおまとめするようなビルドを用意します。

* * *

(2016/10/22)  
説明が色々と足りていなかったようなので、追記します。

@tag1216
さんの回答のように、この回答でのべたプロジェクトの分割は、「インターフェースクラスと実装クラスの分離」を想定しています。ただ、これだけだと今回問題になっている、「開発者が不用意に実装クラスを触らない」は実げんできないと思っています。

具体例を挙げます。永続層用のプロジェクトがあったとして、それが`dao.jar`でビルドされているとします。そして、この dao
プロジェクトの中で、例えばインターフェースと実装クラスを分離したとします。 `dao.jar` の中には両方が入っている状態になります。

アプリケーションロジックを記述するプロジェクトを `application.jar` だとします。 `dao.jar`
の中のインターフェースを利用する必要があるので、 application プロジェクトは、 dao
プロジェクトを依存関係に持つ必要があります。すると、欲しくなかった実装クラスまでついてきます。開発者が、ついうっかり実装ロジックでしか使われる想定しかしていない実装クラスを使ってしまう懸念点は払拭できません。

なので、 dao プロジェクトを分割します。インターフェースのみを持つようなプロジェクト (これを自分は spec と言っていました）と、 spec
に依存を持つような実装プロジェクト（これを自分は impl と言っていました）です。

そして、 application プロジェクトからは dao-spec プロジェクトのみを依存関係に追加します。


CC BY-SA 3.0
2016-10-10T13:30:59.553
29460
2016-10-22T10:08:41.053
2016-10-22T10:08:41.053
754
754
28793
answer


インターフェースと実装クラスに分ければ良いのではないでしょうか。

> ユースケース上必要となるメソッドのみを外部に公開します。

この部分を公開用インターフェースのメソッドとして定義して、

> その内部状態（集約に含まれるエンティティやEnum型フィールド等）は公開せず、

この部分は実装クラスのpublicメソッドにします。

外部にはインターフェースを渡せば、キャストしない限り実装クラスのpublicメソッドをうっかり呼び出すという事は起こりません。

[code]

    public interface Hoge {
        //公開したいメソッド
        public void xxx();
    }
    
    public class HogeImpl implements Hoge {
        @Override
        public void xxx() {
        }
    
        // 公開したくないメソッド
        public void yyy() {
        }
    }
    
[/code]


CC BY-SA 3.0
2016-10-21T00:57:16.237
29754
2016-10-21T00:57:16.237
18862
28793
answer