0

再次,我到达了一些十字路口,这让我与(“丰富”)域模型对象的对象组合设计的正确原则作斗争。

请注意,组合的含义是UML建模带来的含义:当有人声明一个对象包含另一个对象或对象集合时,所包含的对象(或对象集合)的生命是附加到(或依赖于)的容器对象的生命周期。

让我们举一个例子,这样我就可以直接表达我的观点。想象一下,我们有一个存储“食物”请求的食品商店,每个请求是每个元素都由一个或多个订单组成,一个订单由一个食物和一个数量来描述。所以,让我们用 UML 图来说明这个场景 --> http://imageshack.us/photo/my-images/546/5lfa.jpg/

基本上我们有三个类RequestOrderFood。我可能会清楚这一点,在不属于请求的订单中,没有任何可以想象的方法。

在那之后,我开始编码。我到达了两个不同的方案,但在展示这两个方案之间的差异之前,让我们编写通用类 Food。

/**
 * Each object represent diferents types of food.
 */
public enum Food
{
    PIZZA,
    HAMBURGUER,
    ANOTHER_TYPE_OF_FOOD
}

嗯,是的..你说得对,我说这是类......所以是一种具有众所周知的对象的类(毕竟我猜是枚举)。

第一个方案)

这是Order课程

请注意方法equalshashCode

/**
 * An order represent a part of a meal request.
 */
public class Order 
{
    private Food food; // this is one-to-one
    private int  quantity; // the quantity
    private Request request; // this is many-to-one (the ORDER needs to BE WITHIN a Request, if not it can´t exists)

    public Order (Food food,int quantity)
    {
        this.food     = food;
        this.quantity  = quantity;
    }

    public Order (Food food)
    {
        this.food      = food;
        this.quantity  = 0;
    }


    public Food getFood()
    {
        return food;
    }

    public void setFood(Food food)
    {
        this.food = food;
    }

    public int getQuantity()
    {
        return quantity;
    }

    public void setQuantity(int quantity)
    {
        this.quantity = quantity;
    }

    public void incQuantity(int quantity)
    {
        this.quantity += quantity;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (obj == null)
        {
            return false;
        }
        if (getClass() != obj.getClass())
        {
            return false;
        }
        final Order other = (Order) obj;
        if (this.food != other.food) // must be the same food
        {
            return false;
        }
        if (!Objects.equals(this.request, other.request)) // must belong to the same request
        {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode()
    {
        int hash = 3;
        hash = 37 * hash + (this.food != null ? this.food.hashCode() : 0);
        hash = 37 * hash + Objects.hashCode(this.request);
        return hash;
    }
}

这是Request类:

请注意方法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);
        }
    }
}

我真的开始想知道是否正确实例化一个新的订单,让列表使用重新定义的方法进行搜索equalshashCode就像我的东西在某个起点是一个很好的面向 Java 的方法,但这里显示了一些我没有的薄弱侧翼期待。

第二方案)

这是Order类:

请注意,不需要equals 和hashcode,因为我在Request 类中使用了一个map 来进行组合。

/**
 * An order represent a part of a meal request.
 */
public class Order 
{
    private Food food; // this is one-to-one
    private int  quantity; // the quantitfy
    private Request request; // this is many-to-one (the ORDER needs to BE WITHIN a Request, if not it can´t exists)

    public Order (Food food,int quantity)
    {
        this.food     = food;
        this.quantity  = quantity;
    }

    public Order (Food food)
    {
        this.food      = food;
        this.quantity  = 0;
    }


    public Food getFood()
    {
        return food;
    }

    public void setFood(Food food)
    {
        this.food = food;
    }

    public int getQuantity()
    {
        return quantity;
    }

    public void setQuantity(int quantity)
    {
        this.quantity = quantity;
    }

    public void incQuantity(int quantity)
    {
        this.quantity += quantity;
    }

    // No equals and hashcode redefinition needed.
}

这是Request类:

请再次注意方法placeOrder

/**
 * 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));
        }
    }

}

同样,我更喜欢这种方法,但让我怀疑它是否是正确的方法,以及我如何注释以供以后与 JPA 一起使用。

还有一件事。关于这个问题,我真的试图找到一些好的解释以及如何处理这种常见情况。但我总是失败。在Hibernate Quickly中,我没有找到任何线索。我一直读到第 7 章。在Hibernate in action 中,我发现了一些关于 Bid 和 Item 的内容,但没有解决组合问题,而是使用聚合显示示例。(我看到了几篇关于在组合上下文中管理集合的问题的文章,但它并没有提供关于如何解决我在这里陈述的弱实体和强实体问题的线索)

更重要的一件事

请:甚至不要认为可以通过这种方式解决

public class Request
{

    public void place (Order oder) 
    {
        orders.add(oder);
    }
}

上面的方法是使用Aggregation,这样我将创建和销毁委托给另一个不在图片中的上层模块,可能是在服务层中,让我所有的域模型类都非常厌倦,指的是差的类仅包含state的封装行为。这是我不想要的,因为我想要一个丰富的模型,从某种意义上说,其中包含一些业务逻辑,而部分业务逻辑是关于实例化的(这是真实的历史,让我们面对现实吧)。

所以,最后,问题是这样的:

1)什么是最好的方法?显然,我愿意看到新的视角。

2)(更懒惰的问题)为了使用 ORM,我应该用 JPA 对类进行适当的注释吗?

嗯,谢谢大家!

问候。

胜利者!

PD:我的一个非常相关的问题是这个

4

1 回答 1

0

如果您认为第二种方案更接近域,我建议使用混合解决方案。关键是使用 List 进行持久性,而使用 Map 进行域。

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;
    }
}

此解决方案使域模型受持久性实现的影响最小。主要的缺点是这将引入一些将订单列表转换为订单映射的开销。

于 2013-07-09T14:36:25.853 回答