Java 我应该如何组织这些代码(OOP,接口)
我正在尝试创建一个图表的结构。到目前为止,我正在尝试如何为边创建一些类 图中的边可以是 正规的, 定向、加权(或上述任何一项) 那么你认为组织这个类的最佳方式是什么呢?我在考虑创建一个接口IEdge,然后创建类Java 我应该如何组织这些代码(OOP,接口),java,oop,interface,Java,Oop,Interface,我正在尝试创建一个图表的结构。到目前为止,我正在尝试如何为边创建一些类 图中的边可以是 正规的, 定向、加权(或上述任何一项) 那么你认为组织这个类的最佳方式是什么呢?我在考虑创建一个接口IEdge,然后创建类 public interface IEdge{ } public class DirectedEdge implements IEdge{} public class WeightedEdge implements IEdge{} 但现在我遇到了一个问题,它不是很灵活,如果我想要以下
public interface IEdge{
}
public class DirectedEdge implements IEdge{}
public class WeightedEdge implements IEdge{}
但现在我遇到了一个问题,它不是很灵活,如果我想要以下内容呢
public class DirectedWeightedEdge implements IEdge{}
您将如何编写此代码?在此处使用装饰器模式可能比较合适:
基本上,您将拥有一个实现IEdge的基类,以及也实现IEdge接口的DirectedgeDecorator和WeightedgeDecorator类。Decorator类将“包装”基础边缘类,并向其添加附加功能。使用此模式,您可以在一个IEdge上堆叠多个装饰器,一个在另一个之上,以不同的方式修改其行为。为什么要显式创建边?到目前为止,在每个图形实现中,边都隐式地存在于节点对象中。在每个节点中,您都需要一个相邻节点的数组—如果需要对它们进行加权,只需添加一个整数即可 方向也很自然地依此而来(双向图很容易用单向图来表示)。显然,如果图形足够小,也可以将它们保存为邻接矩阵,这对于并行算法来说非常好。。但是如果性能很重要,我们讨论的是完整矩阵无法使用的尺寸 编辑:在评论之后,我想我应该澄清一点:使用一个Edge类来保存关于Edge(颜色、权重)的附加信息是可以的,但我总是将它作为特定节点的一部分使用:例如,类似这样的东西-在C中,我会使用一个struct
class Node {
List<Edge> children;
class Edge {
int weight;
Color color;
Node dest;
}
}
类节点{
列出儿童名单;
阶级边缘{
整数权重;
颜色;
节点dest;
}
}
我将混合使用继承和前面提到的装饰器模式
有向边和无向边的行为完全不同,它们是强制性的,并且相互排斥。因此,它们应该是Edge
接口的唯一两种实现
然而,权重只是可以栓在现有边缘上的东西,因此装饰图案是最适合它们的
但是回到第一步,取决于共享代码定向和无向边的数量,一个Edge
抽象类可能比一个接口更好。当然,“正确”的解决方案是两者兼有:一个接口,由一个抽象类实现,由两个具体类扩展。但在这种情况下,这听起来像是过度工程化。这不是面向对象的练习——我的意思是,首先使用逻辑,然后查看模式。有向图和无向图是非常不同的。有向边有起点和终点,无向边只有两个节点。您可以将它们称为开始和结束,以获得一个公共的基础,但没有向边添加方向性这样的东西
同时,边可能有颜色、权重、价格、长度、容量等。是否确实要实现彩色权重价格边长容量限制ge
?或者你想使用5个装饰器?我希望你不要
我的第一点是,“方向性”并不适合任何模式。您可以使用属性“isDirected”或其他任何东西,并且可能根本不需要它,因为大多数图形不会混合不同类型的边。因此,每个图形的单个属性应该可以。通常,无向边由一对两个有向边表示
我的第二点是,一般来说,重量之类的东西不应该被强行放在边缘。使用映射
作为图形的属性
做得更好。您仍然可以使用像Edge和Node这样的对象,这样可以避免混淆它们(在C中很容易发生这种情况,您可能会使用它们的id
s),但将它们的属性保留在外部。一种类型,两种属性
type Edge
boolean directed = false;
number weight = 1;
可以将边缘信息与邻接信息分开。这意味着您不会复制边数据,而是将它们存储在邻接列表中
public class Node<TEdge> {
class AdjacencyInfo {
Node<TEdge> node;
TEdge edge;
public AdjacencyInfo(Node<TEdge> node, TEdge edge) {
// ....
}
}
bool isDiGraph;
List<AdjacencyInfo> adj;
///.... constructor, other methods
public TEdge ConnectTo(Node<TEdge> node) {
TEdge e = new TEdge();
AdjacencyInfo a0 = new AdjacencyInfo(node, e);
this.adj.Add(a0);
if (!isDiGraph) {
AdjacencyInfo a1 = new AdjacencyInfo(this, e);
node.adj.Add(a1);
}
return e; // return the edge so caller is able to set edge properties (weight, color, etc)
}
}
公共类节点{
类邻接yinfo{
节点;
特奇边缘;
公共邻接YInfo(节点,TEdge边){
// ....
}
}
布尔isDiGraph;
列表;
///..构造函数、其他方法
公共TEdge连接到(节点){
TEdge=新TEdge();
邻接yinfo a0=新的邻接yinfo(节点,e);
本调整加(a0);
if(!isDiGraph){
AdjacencyInfo a1=新的AdjacencyInfo(本,e);
节点调整添加(a1);
}
return e;//返回边缘,以便调用方能够设置边缘属性(重量、颜色等)
}
}
这样的方法应该可以很好地解决定向/非定向问题。我不知道使用Java泛型可以完成多少工作,因为除了避免容器中的类型转换之外,Java泛型在其他方面几乎不可用,但是,如果您需要只处理加权边,则可以通过将权重设置为1或任何有意义的设置来避免泛型。如何使用一个必须显示图形的软件,例如边具有颜色。你能把它也塞进节点吗?当然不是。不,我会使用Edge类,但我永远不会区分定向/无向或其他任何东西。只是一个节点和附加信息(正如我对加权图所说的)——这是一个边实现。你是对的,也许我误解了他对边类的意图。嗯,这是一个有趣的想法,但边总是恰好属于两个节点。因此,在您的实现中,一条边将由两个边对象表示。这可能是有效的,但听起来不太对劲