私は最近、SOLID、デメテルの法則、DDD などのオブジェクト指向の原則/実践/パラダイムについてよく考えてきましたが、表面化し続けているテーマは、オブジェクトのカーディナリティを強制することです。
オブジェクトの関連付けカーディナリティは、特定のエンティティを特定の数の他のエンティティ オブジェクトにのみ関連付けることを義務付けるビジネス ルールから派生します。たとえば、倉庫を管理するシステムを設計している場合、ビジネス ルールとして、1 つのアイテムを 1 つの倉庫にのみ保管できるようにすることができます。明らかに、ソフトウェア設計内でこれらのルールを強制することは、実装の問題です。
私が疑問に思っているのは、ビジネス ドメインで厳格なカーディナリティ モデルが必要な場合、それを実施する最善の方法は何でしょうか? オフハンドで考えられるテクニックには、次のようなものがあります。
双方向参照- 関連付けられたオブジェクト間の双方向の関連付け (オブジェクト A はオブジェクト B を参照し、オブジェクト B はオブジェクト A を参照します)
class Warehouse { private List<Item> items; public void RegisterItem(Item obj) { if(obj.Warehouse != null) throw new ArgumentException("Can only register un-owned item") items.Add(obj); obj.Warehouse = this; } }
所有エンティティをカプセル化する- 所有者がその作成と削除を制御し、実際のエンティティ実装を抽象化する一連の API を介してアクセスを提供できるようにします (オブジェクト A は渡されたエンティティ B を複製するか、渡されたスキーマに基づいてエンティティ B を作成します)。
class Warehouse { private List<Item> items; public void RegisterItem(Item obj) { items.Add((Item)obj.Clone()); } public void RegisterItem(ItemDescriptor item) { items.Add(new Item(item)); } }
サード パーティ モニター- カーディナリティの制約を理解しているサード パーティに、オブジェクトの関連付けを適切に作成および接続してもらいます (オブジェクト C は A と B の関係を認識しており、その作成と維持を担当します。このメソッドは C のみが使用でき、クライアントは使用できません。 )
class Warehouse { private List<Item> items; internal void RegisterItem(Item obj) { items.Add(obj); } } class WarehouseItemRegistrationService { private List<Item> registeredItems; public void RegisterItem(Warehouse warehouse, Item item) { if(registeredItems.Contains(item)) throw new ArgumentException("Can only register un-owned items"); warehouse.RegisterItem(item); } }
どの技術にも長所と短所があると思います。双方向の関連付けにより、オブジェクト グラフが複雑になり、参照を更新するためのプライベート API が必要になる可能性がありますが、実装は非常に簡単で、ビジネス エンティティ クラスにビジネス制約を埋め込むことができます。所有エンティティをカプセル化すると、エンティティに値ベースの説明を強制することでドメイン モデルが複雑になる可能性がありますが、非常にクリーンです。サード パーティの監視手法は、明示的なカーディナリティの適用を別のクラスに分離しますが、ドメイン モデルも複雑にします。
誰か他の考え、アイデア、またはより良いアプローチがありますか?