Java最佳实践:子类中更详细的类变量
我正在用java为一些算法建模一个可绘制的平面图。 我的基本课程是:Java最佳实践:子类中更详细的类变量,java,graph,drawable,Java,Graph,Drawable,我正在用java为一些算法建模一个可绘制的平面图。 我的基本课程是: public class Node { private String label; } 及 这对于算法来说非常有效。为了绘制图形,我使用位置扩展了节点类: public class GraphicalNode extends Node { private int x; private int y; } 我的问题是关于可拉伸边的课程。我想这样写: public class GraphicalEdge
public class Node {
private String label;
}
及
这对于算法来说非常有效。为了绘制图形,我使用位置扩展了节点类:
public class GraphicalNode extends Node {
private int x;
private int y;
}
我的问题是关于可拉伸边的课程。我想这样写:
public class GraphicalEdge extends Edge {
private GraphicalNode node0;
private GraphicalNode node1;
}
public class Node implements Point {
private String label;
// ...
}
Edge edge = new Edge();
// initialization here ...
PointsDrawer pd = new PointsDrawer();
pd.drawPoints(edge.getNodes());
但我以前从未见过这样的设计。除此之外,编译器还需要一个构造函数publicgraphicalnode(node0,node1)
,用于超类
有人知道吗?您可以使用泛型并用Node类参数化Edge
public class Edge<N extends Node> {
private N node0;
private N node1;
public Edge(N n0, N n1) { this.node0 = n0; this.node1 = n1; }
}
公共类边缘{
私有N节点0;
专用N节点1;
公共边(nn0,nn1){this.node0=n0;this.node1=n1;}
}
然后,GraphicalEdge变为
public class GraphicalEdge extends Edge<GraphicalNode> {
public GraphicalEdge (GraphicalNode n0, GraphicalNode n1) { super(n0, n1); }
}
公共类GraphicalEdge扩展边缘{
公共GraphicalEdge(GraphicalNode n0,GraphicalNode n1){super(n0,n1);}
}
注意:这些类型的类层次结构通常很难处理。
您也可以简单地决定将
x
和y
成员放入to节点基类中,而不需要层次结构。我认为最简单的方法是让节点
类实现点
:
public interface Point {
double getX();
double getY();
}
像这样:
public class GraphicalEdge extends Edge {
private GraphicalNode node0;
private GraphicalNode node1;
}
public class Node implements Point {
private String label;
// ...
}
Edge edge = new Edge();
// initialization here ...
PointsDrawer pd = new PointsDrawer();
pd.drawPoints(edge.getNodes());
然后您可以拥有一个类似于原始类的Edge
类:
public class Edge {
private Node node0;
private Node node1;
public List<Node> getNodes() {
// ...
}
使用此选项,可以将图形逻辑从数据结构中分离出来,只需在节点
类中保留x和y坐标即可。您可以通过使用装饰器或地图存储附加的点
数据来进一步解耦它
也许我误解了这里的某些内容-下面的投票将显示-但是
这听起来像是一个教科书上使用的例子
当您有一个类Edge
具有一个方法Node getNode()
,那么您可以在一个扩展Edge
的类中为该方法定义一个更具体的返回类型。例如:
class Node {}
class Edge {
Node getNode();
}
class GraphicalNode extends Node {}
class GraphicalEdge extends Edge {
// This really overrides the method, with a more specific return type!
@Override
GraphicalNode getNode();
}
或者,使用您提供的类,使用您提到的构造函数和一些getter进行扩展,组装成:
这里的关键点是:当您有一个
Edge
类型的引用时,您只能从中获取一个节点
(即使引用实际引用的对象是一个图形边缘
)。仅当引用类型为GraphicalEdge
时,您还可以从中获取GraphicalNode
这在许多上下文中都很方便,并且通常允许清晰地分离关注点:当方法只需对边
和节点
对象进行操作,并且对它们的图形表示不感兴趣时,可以使用基类编写其签名:
void computeSomething(Edge edge) {
Node n0 = edge.getNode();
Node n1 = edge.getNode();
...
}
void run() {
GraphicialEdge e = new GraphicalEdge(...);
computeSomething(e);
}
当一个方法确实需要图形表示时,可以让它使用图形边缘:
void drawSomething(GraphicalEdge edge) {
GraphicalNode n0 = edge.getNode();
GraphicalNode n1 = edge.getNode();
...
}
void run() {
GraphicialEdge e = new GraphicalEdge(...);
computeSomething(e); // Works
drawSomething(e); // Works as well
Edge edge = e;
drawSomething(edge); // Does not work. A GraphicalEdge is required.
}
考虑到你的问题特别是关于 类变量: 根据您在此处绘制的当前设计,每个
GraphicalEdge
将存储其节点两次——一次作为GraphicalNode
,一次作为简单的节点。例如,可以通过将事物定义为接口来避免这种情况:
interface Node {}
interface Edge {
Node getNode();
}
interface GraphicalNode extends Node {}
interface GraphicalEdge extends Edge {
@Override
GraphicalNode getNode();
}
class DefaultEdge implements GraphicalEdge { ... }
例如,使用泛型可能会增加更多的自由度,考虑到进一步的节点
类型,可能会有更干净、更灵活的设计。例如,您以后可能希望引入类似于ColoredGraphicalNode
的内容,泛型类型参数可以很好地涵盖这一点。但它的代价是更为神秘的方法签名:以泛型形式编写方法,允许“路由”所需的类型信息可能会变得有点麻烦,这取决于您要走多远。eh?我真的听不懂你在说什么。因为你的图形节点
是一个节点
,您可以将其存储在Edge
的成员中,并向GraphicalEdge
添加两个getter,这两个getter在访问GraphicalNode
@AndreasFester时封装了强制转换,但是如果在GraphicalEdge中存储一个真实节点而不是一个GraphicalNode,我会冒ClassCastException的风险,不是吗?是的,这就是缺点-您需要确保存储正确的对象。您可以通过@wero使用基于泛型的方法-在那里,编译器确保您只将GraphicalNodes
存储到GraphicalEdges
中。在任何情况下:避免子类中的成员重复。谢谢。我认为在这种情况下,weros方法是最明智的。谢谢你的想法。这看起来很有趣。我考虑这个解决方案。我不想把x和y放在节点上,因为如果我只使用图的模型而不使用图的视图,我就不需要它们了。谢谢。但这与在节点中存储x和y坐标是相同的问题。如果我只想使用一个图的模型,那么坐标会包含很多信息。地图也是一个可能的解决方案。我只想使用尽可能少的数据结构。作为一个类变量,我不需要地图。你可以像这样把坐标放在map
中:map
我在另一块板上得到了部分相同的答案,我问了一个问题:D我没有得到协方差的方法。这是我最喜欢的!非常感谢你!