Java 如何在删除时设计多对多关系?

Java 如何在删除时设计多对多关系?,java,oop,gwt,many-to-many,java-canvas,Java,Oop,Gwt,Many To Many,Java Canvas,我正在创建一个带有两个对象的画布图形:矩形,以及连接矩形的线条。每一行都应该知道它所连接的2个矩形。 每个矩形可以有多条线将其连接到其他矩形s class Rectangle { List<Line> connections; void setConnection(Line line) { connections.add(line); } } class Line { Rectangle from, to; public L

我正在创建一个带有两个对象的
画布
图形:
矩形
,以及连接矩形的
线条。每一行都应该知道它所连接的2个矩形。
每个
矩形
可以有多条线将其连接到其他
矩形
s

class Rectangle {
    List<Line> connections;
    void setConnection(Line line) {
        connections.add(line);
    }
}

class Line {
    Rectangle from, to;

    public Line(Rectangle from, Rectangle to) {
        this.from = from;
        this.to = to;

        from.setConnection(this);
        to.setConnection(this);
    }
}
类矩形{
列出连接;
无效设置连接(线路){
连接。添加(行);
}
}
班级线{
矩形从,到;
公用线(矩形从、矩形到){
this.from=from;
这个;
from.setConnection(this);
to.setConnection(本);
}
}
我觉得这可能不是一个好的设计,因为当我删除
时,我还必须从它连接的
矩形
中的连接列表中删除

当我删除一个
矩形
时,我还必须删除连接到该矩形的
,因为它们不应该存在。因此,我必须遍历可删除的
矩形
的所有
连接
,对于每个
连接
,从
/
矩形
,然后再次获取
连接
列表并删除
引用

我的问题不是写代码(我已经让它工作了),但在我看来,我做了很多来回的引用


这能做得更好吗?不知何故:如果删除了一个矩形,那么线的所有深连接都会自动删除/失效?类似于Hibernate的多对多级联?我不能只使用Hibernate,因为这应该是一个客户端应用程序,没有数据库。

基本上你是在构建图形。需要将边与顶点分开

让我们先创建一些接口来分离一些关注点:

interface Shape {
}

interface ShapeConnection {
    Shape[] getConnectedShapes();
}
然后,让我们介绍一个注释,该注释将标记需要级联删除其连接形状的形状

@interface CascadeDeleteConnectedShapes {
}
然后可以将矩形和直线定义为:

@CascadeDeleteConnectedShapes
class Rectangle implements Shape {

}

class Line implements Shape, ShapeConnection {
    Rectangle from, to;

    public Line(Rectangle from, Rectangle to) {
        this.from = from;
        this.to = to;
    }

    @Override
    public Shape[] getConnectedShapes() {
        return new Shape[] { from, to };
    }
}
最后,你将需要一个地方,你可以把它放在一起

class Canvas {
    private ConnectionManager connectionManager = new ConnectionManager();

    private Set<Shape> shapes = new HashSet<Shape>();

    public Canvas() {
    }

    public void removeShape(Shape shape) {
        if (!shapes.remove(shape))
            return; 

        if (shape.getClass().isAnnotationPresent(CascadeDeleteConnectedShapes.class)) {
            cascadeDeleteShape(shape);
        }

        if (shape instanceof ShapeConnection) {
            connectionManager.remove((ShapeConnection) shape);
        }
    }

    private void cascadeDeleteShape(Shape shape) {
        List<ShapeConnection> connections = connectionManager.getConnections(shape);
        for (ShapeConnection connection : connections) {
            if (connection instanceof Shape) {
                this.removeShape((Shape) connection);
            } else {
                connectionManager.remove(connection);
            }
        }
    }

    public void addShape(Shape shape) {
        if (shapes.contains(shape))
            return;

        if (shape instanceof ShapeConnection) {
            addShapeConnection((ShapeConnection) shape);
        }

        shapes.add(shape);
    }

    private void addShapeConnection(ShapeConnection shapeConnection) {
        for (Shape shape : shapeConnection.getConnectedShapes()) {
            if (!shapes.contains(shape))
                throw new Error("cannot connect unknown shapes");
        }
        connectionManager.add(shapeConnection);
    }
}
类画布{
私有连接管理器ConnectionManager=新连接管理器();
私有集形状=新HashSet();
公共画布(){
}
公共空间移除形状(形状){
如果(!shapes.remove(shape))
返回;
if(shape.getClass().isAnnotationPresent(CascadeDeleteConnectedShapes.class)){
形状(形状);
}
if(ShapeConnection的形状实例){
connectionManager.remove((ShapeConnection)形状);
}
}
私有空心形状(形状形状){
List connections=connectionManager.getConnections(shape);
for(ShapeConnection连接:连接){
if(形状的连接实例){
此。移除形状((形状)连接);
}否则{
connectionManager.移除(连接);
}
}
}
公共空心形状(形状){
if(shapes.contains(shape))
返回;
if(ShapeConnection的形状实例){
addShapeConnection((ShapeConnection)形状);
}
形状。添加(形状);
}
私有void addShapeConnection(ShapeConnection ShapeConnection){
对于(形状:shapeConnection.getConnectedShapes()){
如果(!shapes.contains(shape))
抛出新错误(“无法连接未知形状”);
}
connectionManager.add(shapeConnection);
}
}
形状可以同时是形状连接。将几个矩形添加到画布后,可以添加线来连接它们。由于设计中的一条线被识别为
ShapeConnection
,因此涉及该线的任何操作都将调用
Canvas
以让
ConnectionManager
处理图形。在这种设计中,
是不可变的,这一点很重要

级联是通过删除带注释的形状触发的。您需要小心地管理这些级联:如果在过程中的某个地方发生异常,您将得到一个不完整的图

这段代码只是给你一个想法。另外,我将把连接管理器的实现留给您想象。其中一条评论提到了番石榴。A本可以正好达到你的目的,可惜他们还没有发布。无论如何,我肯定会考虑让现有库处理
ConnectionManager
的细节;很多都是适合你需要的


请注意,此设计中不存在任何连接。

为了删除深层连接,需要以某种方式对其进行评估。您可以像以前一样在删除时进行检查,也可以让它在访问时进行检查(将指针设置为null,然后,当有人试图访问它并看到null时,它会删除该行)。这样可以节省初始删除的时间,但每次访问都会增加一点开销,如果您实际上不访问它们,则会使用更多内存。与垃圾收集()问题非常类似,您可以使用
映射
,其键类型为
矩形
,值为
对象的
集合(或番石榴
多映射
)。如果有很多矩形和直线,这可以显著提高性能。当然,您可以从
矩形
类中删除
列表
。实际上,我想我可能会引入一个类来管理“连接点”,并包含矩形/直线的映射。(顺便说一句,我认为在使用
GWT编程时,最好使用一个具体的类,比如
ArrayList
,而不是抽象类
List