如何设计删除时的多对多关系



我正在创建一个具有2个对象的canvas绘图:RectanglesLines连接矩形。每条线路都应该知道它所连接的2个Rectangle。每个Rectangle可以有多条线连接到其他Rectangle

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

我觉得这可能不是一个好的设计,因为当我删除Line时,我也必须从它连接的Rectangle的连接列表中删除Line

当我删除Rectangle时,我也必须删除连接到矩形的Line s,因为它们不应该存在。因此,我必须遍历可删除的Rectangle的所有connections,并且对于每个connection获得from/to rectangle,然后再次获得connection列表并删除Line引用。

我的问题不是写代码(我已经让它工作了),但对我来说,我似乎做了很多来回引用。

还能做得更好吗?不知何故:如果一个矩形被删除,那么所有的深度连接从线被删除/自动失效?类似于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);
    }
}

一个形状可以同时是一个形状连接。一旦在画布上添加了几个矩形,就可以添加线条来连接它们。由于设计中的一条线被识别为ShapeConnection,因此涉及该线的任何操作都将调用Canvas以让ConnectionManager处理图形。在这个设计中,重要的是Line是不可变的。

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

这段代码只是给你一个想法。此外,我将把连接管理器的实现留给您的想象。其中一条评论提到了番石榴。一个BiMultiMap可以很好地满足你的需求,可惜他们还没有发布。在任何情况下,我肯定会考虑让ConnectionManager的具体细节由现有的库处理;已经写了很多适合你需要的。

最新更新