1


我有一些实体类与其他实体具有一对一和/或一对多的关系。

我尝试制作一个非常通用的示例来反映我的情况......假设我将以下表存储在数据库中(不允许空值):

   operations (ID, workerID, customerID, etc_etc)
      workers (ID, email, password, etc_etc)
    customers (ID, etc_etc)
 mobilePhones (workerID, phoneNumber)

应该很清楚的是:

  • 1 个操作只有 1 个工人和1 个客户。
  • 1位客户至少有 1 个手机号码。

因此我有以下实体类:

public class Customer {
    private int id;
    //other fields, then constructors, getters and setters
}

public class Worker {
    private int id;
    //other fields
    private String[] mobilePhones;
}

正如我在标题中已经说过的,我不能使用Hibernate 之类的 ORM,所以我将使用 DAO。
{编辑:我应该知道你很想知道为什么我不能使用 ORM ......好吧,正如我在下面的评论中写的:这是一项作业(软件工程考试的项目)。}

现在,我想我不会有任何问题,它可以通过从所有电话号码中选择等于实际工人 ID 的WorkerDAO方式轻松管理一对多关系。mobilePhonesworkerID

对我来说真正的问题是如何管理 anOperation与其关联WorkerCustomer. 如果我想避免浪费内存,我应该这样设计我的Operation实体:

public class Operation { // here I have some doubts
    private int id;
    private int workerId;
    private int customerId;
    //other fields
}

或者可能是这样的:

public class Operation { // here I have some doubts
    private int id;
    private Worker worker;
    private Customer customer;
    //other fields
}

?

后者似乎更面向对象,但有一个微不足道的含义:工作者和客户的实例必须在内存中,即使客户Operation可能不需要它们。

更糟糕的是:如果OperationDAO将 worker 和 customer 设置为新的 Worker 和 Customer 实例,这将导致在内存中保留多个引用同一个 worker/customer 的实例(例如,由同一个 worker 执行的两个操作)。除了内存浪费之外,这肯定会导致数据不一致(例如,一个实例被修改而没有更新其他实例)。

为了避免这种情况,应该引入一些知道当前加载了哪些实例的类(例如,使用类似 , 等的东西List<Worker>List<Customer>......老实说,这在我看来是一种矫枉过正。

我还认为我可以尝试实现某种惰性获取,例如仅在第一个请求时设置工作实例,但我仍然需要一些类来跟踪内存中的内容以及必须查询的内容;我什至不知道这个类是否应该与数据访问逻辑业务逻辑相关(我猜是前者,但仍然不确定)。

无论如何,没有理由实现所有这些,因为我不需要缓存系统(而且我觉得它看起来很像那样)。

有什么建议吗?

4

4 回答 4

1

您不能使用框架,但可以使用框架本身使用的模式。因此,我向您推荐这些基于EAA 的 P 的解决方案。马丁·福勒

  1. 您可以使用您的第一个选项(带有 workerId 和 customerId 字段的操作)并为每个实体(操作、工人、客户)使用行数据网关。现在,如果内存是一个问题并且您的模型需要它,请使用Identity Map控制所有 Worker 和 Customer 加载的实例,并避免重新加载。

  2. 您可以使用您的第二个选项(在操作中有一个工作人员和客户实例)并使用带有延迟加载的表数据网关仅在需要时加载实例。

担心是否加载多个实例取决于您正在构建的应用程序的类型和实例的范围;例如,如果你是一个创建基于 CRUD 的应用程序,你的实例通常会有一个请求范围,所以使用第二种方法,不要担心内存浪费或数据不一致。

建议:使用接口来定义你的类型。

于 2012-08-22T14:16:24.783 回答
0

我自己回答,呵呵。

参考我在 davidmontoyago 答案的评论中解释的问题,我认为实现我的目标的最简单方法可能如下:

  • 有一个类来跟踪已从数据库加载并在内存中的实例。这可能是一种实用程序类,我的意思是私有构造函数和所有静态方法。
  • 确保所有返回实体类实例的 DAO 检查请求的实例是否在缓存中;如果是,他们返回该实例,否则他们从数据库加载它并将其添加到缓存中。

我尝试绘制一些代码:

/* The class that will cache istances. */
static final class Cache { // package-private, so that only DAOs can see it.
    private static final int CAPACITY = 100; // max 100 istance per entity

    /* I will track each instance by its id, that is an Integer */
    private static Map<Integer,Worker> workers;
    private static Map<Integer,Customer> customers;
    private static Map<Integer,Operation> operations;

    private Cache() {} // I don't really need to istantiate this class

    // SOME OPERATIONS

    public static boolean isCached(Worker w);
    public static boolean isCached(Customer c);
    public static boolean isCached(Operation o);

    public static Worker getWorker(int id);
    public static Worker getCustomer(int id);
    public static Worker getOperation(int id);

    public static void addWorker(Worker w);
    public static void addCustomer(Customer c);
    public static void addOperation(Operation o);

}

class DAOWorkerImpl implements DAOWorker {
    public find(int id) {
        Worker w = null;
        if (Cache.isCached(id))
            w = Cache.getWorker(id);
        else {
            //retrieve worker
            Cache.addWorker(w);
        }
        return w;
    }
}

你怎么看待这件事?它看起来很简单,它应该完成它的工作。

顺便说一句,在编写这段代码时,我认为最好避免编写Cache类并让管理所有到它们各自的 DAO(例如DAOWorker管理内存中的实例Worker等)。

唯一不能说服我的是,这可能会破坏单一责任原则......你怎么看?

于 2012-08-23T12:45:43.580 回答
0

通常我更喜欢

public class Operation { 
    private int id;
    private Worker worker;
    private Customer customer;
    //other fields
}

因为这更加面向对象并且使获取更容易。但是由于您与ORM特别遥远(我不知道为什么???)所以看起来

public class Operation { 
    private int id;
    private int workerId;
    private int customerId;
    //other fields
}

成为更好的选择,您可以在需要时加载对象。

ORM 本来是首选... :)

于 2012-08-21T17:27:48.893 回答
0

我会使用 Spring JDBC 或模板方法模式的其他一些实现。每个实体 1 个 DAO 类。关于事务问题,您可以通过在 JDBC 连接上调用 setAutoCommit(false) 并处理所有查询的结果来简单地自己管理它们。

祝你重新发明轮子好运:]

于 2012-08-21T16:31:43.957 回答