休眠、子类化和访客模式



我可能用错了词,所以当我说业务对象(BO)时,我指的是一个类,它引用了映射到具有Hibernate的数据库表的类以及业务逻辑。

我面临的问题是在不使用反射或实例的情况下为子类实例化正确的 BO。

例如,假设我有一个笔桌,其中包含对动物表的单个引用,而动物表又有两个子表猫和狗(都是一对一的引用)。这些类看起来有点像这样:

public class Pen {
    private Animal a;
    // Getters and setters
}
public class Animal {
    // Getters and setters
}
public class Dog extends Animal {
    // Getters and setters
}
public class Cat extends Animal {
    // Getters and setters
}
public class PenBO {
    private Pen p;
    public AnimalBO getAnimalBO() { ... }
}
public interface Action {
    void visit(DogBO dbo);
    void visit(CatBO cbo);
}
public class Sound implements Action {
    void visit(DogBO dbo) { ... }
    void visit(CatBO cbo) { ... }
}
public interface AnimalBO {
    void accept(Sound s);
}
public class DogBO implements AnimalBO {
    Dog d;
    void accept(Sound s) {
        s.visit(this);
    }
}
public class CatBO implements AnimalBO {
    Cat c;
    void accept(Sound s) {
        s.visit(this);
    }
}

然后我只是使用 BO 在 BO 的 get 方法中像这样实例化它们:

Pen p = ... // Get or load from database 
PenBO pbo = new PenBO();
pbo.setPen(p);

然后我像这样使用类:

pbo.getAnimalBO().accept(new Sound());

这是我正在研究的getAnimalBO方法。我希望它基于笔的动物实例返回正确的 BO 实例。

我"可以"使用从当前笔检查实际动物的实例,但这显然不漂亮。我想到的另一种选择是使用反射来获取类名并在之后添加"BO"并得到一个实例,但它也非常丑陋。

我尝试在getAnimalBO周围包装另一个访问者模式,但是如果不进行强制转换,它就无法选择正确的访问方法,并且我不想将接受方法添加到非BO类中。

如果没有聪明的方法来使该方法高效工作,那么核心是出了问题吗?我还没有真正找到任何Hibernate的最佳实践。Hibernate和访问者模式的一些示例只是将接受方法添加到映射的类中,这不可能是好的......

您的问题实际上只是一个继承的 OO 问题,并且从一个类层次结构转换为一个并行类层次结构。您已经解决了这个问题和 Hibernate 映射的数据库建模,并且您的访问者实现显然没有错。只是您不想将访问者模式应用于映射的类层次结构,因此您在两个层次结构之间转换时遇到了问题。

就目前而言,您的代码的一部分将不得不负责知道CatBO对应于Cat等,并且知道如果Pen对象的Animal属性实际上是Cat,那么包含PenBO对象的AnimalBO属性实际上将是一个CatBO。鉴于此,它必须能够确定返回的Animal实例的类型,因此我看不出如何避免使用instanceof或反射之一。你对instanceof有什么异议?我同意,反思以获取类名并附加"BO"是非常令人讨厌和丑陋的,尽管它显然可以工作。但是,恕我直言,负责采用Animal并通过使用instanceof并选择正确的BO类来返回合适的AnimalBO的单一方法并不是一件坏事。

我想问的问题是,为什么要像这样从一个类层次结构映射到另一个类层次结构。您说过您不想将accept方法添加到映射类中,并且它"不可能是好的",但您还没有证明为什么会有这种感觉。它比你已经展示给自己的选项更糟糕吗?通过将访问者模式添加到映射的类层次结构中,您并没有真正在那里嵌入任何业务逻辑,您只是使用访问者模式在整个层次结构中启用业务逻辑的应用。因此,您的业务逻辑层包含简单的通用访问者实现,您的映射类或域层是POJO加上基本的访问者实现,并且您实际上确实具有我认为您想要的漂亮干净的分离。

最新更新