使用JPA管理复合对象并正确映射其属性
再一次,我遇到了一些十字路口,这些十字路口让我与“丰富”领域模型对象的对象组合设计的正确原则作斗争 请注意,组合的含义是UML建模带来的含义:当有人声明一个对象包含另一个对象或一组对象时,所包含对象(或一组对象)的生命附加到(或取决于)容器对象的生命 让我们举个例子,这样我就可以直接展示我的观点。假设我们有一家食品店,它存储“食品”请求,每个请求都是由一个或多个订单组成的,订单仅由一个食品和一个数量来描述。所以,让我用UML图来演示这个场景--> 基本上我们有三类:使用JPA管理复合对象并正确映射其属性,jpa,domain-driven-design,domain-model,object-composition,Jpa,Domain Driven Design,Domain Model,Object Composition,再一次,我遇到了一些十字路口,这些十字路口让我与“丰富”领域模型对象的对象组合设计的正确原则作斗争 请注意,组合的含义是UML建模带来的含义:当有人声明一个对象包含另一个对象或一组对象时,所包含对象(或一组对象)的生命附加到(或取决于)容器对象的生命 让我们举个例子,这样我就可以直接展示我的观点。假设我们有一家食品店,它存储“食品”请求,每个请求都是由一个或多个订单组成的,订单仅由一个食品和一个数量来描述。所以,让我用UML图来演示这个场景--> 基本上我们有三类:Request、Order和F
Request
、Order
和Food
。请允许我澄清一下,没有一种可以想象的方式来处理不属于请求的顺序
之后,我开始编写代码。我得出了两个不同的方案,但在展示两个方案之间的差异之前,让我们先写下共同类食物
/**
* Each object represent diferents types of food.
*/
public enum Food
{
PIZZA,
HAMBURGUER,
ANOTHER_TYPE_OF_FOOD
}
嗯,是的。。你说得对,我说过那是一门课。。。这是一种具有广为人知的对象的类(毕竟,我想枚举是关于对象的)
(第一项计划)
这是订单
类
请注意方法等于和hashCode
这是请求
类:
请注意方法placeOrder
/**
* An instance of Request represents a concrete meal request, belonging to a client, that may include various types of food.
* NOTE : The request is _composing_ order objects. Order object instantiation and destruction is handled INSIDE this class only.
*/
public class Request
{
private List<Order> orders; // one-to-many, with COMPOSITION, so the Request OWNS each order (not AGGREGATION) (the ORDER needs to BE WITHIN a Request, if not it can´t exists)
public Request()
{
}
public void placeOrder (Food food, int quantity)
{
Order order = new Order(food, quantity);
int index = orders.indexOf(order);
if (index != -1)
{
Order storedOrder = orders.get(index);
storedOrder.incQuantity(quantity);
}
else
{
orders.add(order);
}
}
}
/**
* An instance of Request represents a concretre request for food in behalf of a client.
* NOTE : The request is _composing_ order objects. Order objetc instancition and destruction
* is handled INSIDE this class only.
*/
public class Request
{
private Client client; // one-to-one
private Map<Food,Order> orders; // one-to-many, so the Request OWNS each order (not AGGREGATION) (the ORDER needs to BE WITHIN a Request, if not it can´t exists)
public Request()
{
}
public void placeOrder (Food food, int quantity)
{
if (orders.containsKey(food))
{
orders.get(food).incQuantity(quantity);
}
else
{
orders.put(food, new Order(food, quantity));
}
}
}
这是请求
类:
请再次注意,方法placeOrder
/**
* An instance of Request represents a concrete meal request, belonging to a client, that may include various types of food.
* NOTE : The request is _composing_ order objects. Order object instantiation and destruction is handled INSIDE this class only.
*/
public class Request
{
private List<Order> orders; // one-to-many, with COMPOSITION, so the Request OWNS each order (not AGGREGATION) (the ORDER needs to BE WITHIN a Request, if not it can´t exists)
public Request()
{
}
public void placeOrder (Food food, int quantity)
{
Order order = new Order(food, quantity);
int index = orders.indexOf(order);
if (index != -1)
{
Order storedOrder = orders.get(index);
storedOrder.incQuantity(quantity);
}
else
{
orders.add(order);
}
}
}
/**
* An instance of Request represents a concretre request for food in behalf of a client.
* NOTE : The request is _composing_ order objects. Order objetc instancition and destruction
* is handled INSIDE this class only.
*/
public class Request
{
private Client client; // one-to-one
private Map<Food,Order> orders; // one-to-many, so the Request OWNS each order (not AGGREGATION) (the ORDER needs to BE WITHIN a Request, if not it can´t exists)
public Request()
{
}
public void placeOrder (Food food, int quantity)
{
if (orders.containsKey(food))
{
orders.get(food).incQuantity(quantity);
}
else
{
orders.put(food, new Order(food, quantity));
}
}
}
上述方法使用的是聚合,通过这种方式,我将创建和销毁工作委托给了另一个超出范围的上层模块,可能是服务层中的一个模块,这使得我的所有域模型类都非常匮乏,指的是封装行为差、只包含状态的类。这是我不想要的,因为我想要一个丰富的模型,在这个意义上,in包含一些业务逻辑,部分业务逻辑是关于实例化的(这是一个真实的历史,让我们面对it人员)
最后,问题是:
1) 最好的方法是什么?显然,我愿意看到新的视角
2) (更懒散的问题)为了使用ORM,我应该给类添加JPA注释吗
好吧,谢谢大家
格雷廷斯
维克托
我的一个非常相关的问题是 如果您认为第二种方案更接近域,我建议您使用混合解决方案。关键是使用列表表示持久性,而使用映射表示域
public class Request {
private List<Order> orders = new ArrayList<Order>(); //this is easy to persist
public void placeOrder (Food food, int quantity) {
//uses orders() everytime you want to manipulate the orders
final Map<Food, Order> orders = orders();
if (orders.containsKey(food)) {
orders.get(food).incQuantity(quantity);
} else {
orders.put(food, new Order(food, quantity));
}
}
private Map<Food, Order> orders() {
final Map<Food, Order> map = new HashMap<Food, Order>();
for (Order order: this.orders) {
map.put(order.getFood(), order);
}
return map;
}
}
公共类请求{
private List orders=new ArrayList();//这很容易持久化
公共订单(食品,整数数量){
//每次要操作订单时都使用orders()
最终地图订单=订单();
if(订单.集装箱(食品)){
订单。获取(食物)。增加数量(数量);
}否则{
下单。下单(食品、新订单(食品、数量));
}
}
私人地图订单(){
final Map=new HashMap();
for(订单:this.orders){
map.put(order.getFood(),order);
}
返回图;
}
}
此解决方案使域模型受持久性实现的影响最小。主要的缺点是,这将为将订单列表转换为订单映射带来一些开销
public class Request {
private List<Order> orders = new ArrayList<Order>(); //this is easy to persist
public void placeOrder (Food food, int quantity) {
//uses orders() everytime you want to manipulate the orders
final Map<Food, Order> orders = orders();
if (orders.containsKey(food)) {
orders.get(food).incQuantity(quantity);
} else {
orders.put(food, new Order(food, quantity));
}
}
private Map<Food, Order> orders() {
final Map<Food, Order> map = new HashMap<Food, Order>();
for (Order order: this.orders) {
map.put(order.getFood(), order);
}
return map;
}
}