坚持树有苹果的事实

时间:2009-06-30 22:37:44

标签: architecture oop

如果我有一棵有苹果的树,我应该如何模拟苹果树所拥有的这一事实。考虑将有3个数据库表:tree,apple,tree_apples。

在我看来,会有一个AppleDecorator类,以便Tree可以有多个AppleDecorator并调用 - > save(),每个将把关联写入tree_apples。 Apple不知道它归Tree所有。

除了获取所有树的ID之外,从Tree类引用tree_apples表似乎是错误的,因为Tree类为每种类型的对象引用一个表(并且需要存储这样的事实:它有一个)。即使获得Ids也可以卸载到像Iterator这样的东西。

应用程序需要存储一个对象拥有N个其他对象这一事实的情况如何? (在这种情况下,我的类需要存储5种其他类型对象的关联。)

3 个答案:

答案 0 :(得分:5)

tree_apples仅在苹果可以属于多个树时才有效。 (m:n关系)

可能只是一个不好的比喻,但如果我们坚持1树有很多苹果,在关系数据库中通常苹果存储对它来自的树的引用。

Tree
  TreeId
  TreeName

Apple
  AppleId
  IsRotten
  TreeId (foreign key)

对于数据的内存模型(即面向对象),您可能有也可能没有从Apple到Tree的后向指针。即你通常有tree.Apples苹果是某种Apple对象的集合,但你经常有apple.Tree。

答案 1 :(得分:2)

将苹果放在树上的列表或集合中。

如果您正在使用O / R映射器,则可以使用tree_appes表作为连接表来注释或指示列表是一对多的苹果。可以使用苹果列表的级联保存(在树中)保存连接。

答案 2 :(得分:1)

为了做到这一点,我会有另一个结构:

public interface ITreeSaver {

  public void save(Tree t);
  public Tree load(String treeId);

}

然后,您可以以任何方式实现此(原始DAO)。使用Hibernate,可以调用MySQL驱动程序,XStream或其他任何内容。

Tree,Apple或任何其他模型对象无需了解/了解它是如何保存或加载的。

使用直接SQL调用实现此操作将采用以下内容:

public class SQLTreeSaver implements ITreeSaver {

    public void save(Tree t) {

        String id = t.getId();
        if(id == null || id.isEmpty()) {
            id = /*generate Id here*/;
        }

        SQL.execute("delete from TREES where id="+id);
        SQL.execute("insert into TREES values (id, prop1, prop2) ("+id+",'"+t.getProp2()+"','"+t.getProp3()+"'");

        SQL.execute("delete from APPLES where treeId="+id);

        for(Apple a : t.getApples()) {
            String appleId = a.getId();
            if(appleId == null || appleId.isEmpty()) {
                appleId = /*generate Id here*/;
            }           
            SQL.execute("insert into APPLES values (id, tree, prop1) ("+appleId+","+id+",'"+a.getProp1()+"'");
        }

    }

    public Tree load(String id) {

        Tree t = new Tree();

        if(id == null || id.isEmpty()) return t;

        ResultSet treeSet = SQL.execute("select top 1 * from TREES where id="+id);

        while(treeSet.hasNext()) {
            t.setId(treeSet.getString("id"));
            t.setProp1(treeSet.getString("prop1"));
            t.setProp2(treeSet.getString("prop2"));

            ResultSet appleSet = SQL.execute("select * from APPLES where tree="+id);

            ArrayList<Apple> appleList = new ArrayList<Apple>();

            while(appleSet.hasNext()) {
                Apple a = new Apple();
                a.setId(appleSet.getString("id");
                /* omit the following if your apples have no idea who they belong to */
                a.setTree(id);
                a.setProp1(appleSet.getString("prop1"));

                appleList.add(a);
            }

            if(appleList.size() > 0) {
                treeSet.setApples(appleList);
            }

        }

        return t;
    }

}

请原谅不好的SQL调用,因为我只想说明这一点。我们的想法是,您已经从保存/加载界面中抽象出了 对象的保存方式。你可以很容易地进入一些Hibernate。

public class HibernateTreeSaver implements ITreeSaver {

    public void save(Tree t) {
        HibernateHelper.getSession().save(t);
    }

    public Tree load(String id) {
        Tree t = (Tree)HibernateHelper.getSession.load(id);
        return t;
    }

}

现在......你可以看到我想要的东西。您提供了某种方法来选择使用哪种ITreeSaver实现,然后您就具有一定的灵活性或适应性。如果您的客户端使用Hibernate不支持的数据库,该怎么办?如果他们使用平面文件怎么办?为了付出更多的努力,我得到了我认为非常好的关注点分离以及轻松响应和改变以适应系统新情况或需求的能力。