【发布时间】:2015-08-11 18:52:48
【问题描述】:
我正在用 Java 设计一个图形对象。我是设计师,我怀疑这种设计违反了封装,但我想从其他人那里得到一些见解。
在下面,我们有两个接口 Graph 和 Vertex。
图实现负责管理图中的顶点,包括创建、删除、确保施加约束等。通用参数代表T类型,即存储在一个顶点,W8 是存储在边中的权重类型:
public interface Graph<T, W>
{
/** Creates and adds a vertex with the value given to this graph */
Vertex<T> createVertex(T value);
/** Performs some arbitrary modification to the vertex given */
void modify(Vertex<T> vertex, ....);
// some other methods...
}
Vertex 接口用于获取和修改顶点的属性以及保持引用;它的实现由图的实现决定——客户端对其内部实现一无所知。它可能看起来像这样:
public interface Vertex<T>
{
int getValue();
/** Performs some arbitrary modification to this vertex - same as
* as in modify method in graph */
void modify(...);
// some other methods
}
我使用顶点接口的原因是客户端可以简单地保留对相关顶点的引用并将引用传递给图形。我也可以有这样的图形界面:
public interface Graph<T, W>
{
/** Creates and adds a vertex with the value given to this graph */
void createVertex(T value);
/** Performs some arbitrary modification to the vertex given */
void modify(T vertex);
// some other methods...
}
在这个图形界面中,“修改”方法总是需要搜索顶点;这将是非常不切实际的,尤其是当我们想经常修改同一个顶点时——相反,客户端可以像第一种方法一样保留一个参考通道。
回到我的问题,我对封装非常严格,这是否违反了封装的原则?
我个人认为这不会违反封装,因为客户端不知道图形对象或顶点在内部执行了什么。然而,我们确实泄漏了图以某种方式使用顶点的信息(尽管 exact 内部结构没有暴露),其他库没有这样做。示例可能是作为 Graph 子集的数据结构,例如 Trees 和 LinkedLists:核心 Java 库中的 LinkedList 实现不会让应用程序注意到使用了某些 Node 接口;我在其他各种库中看到的树实现也不公开它们的节点。
那么在严格的面向对象术语下,这种设计是否违反封装?我也欢迎对现有的面向对象库(也在 Java 范围之外)或讨论该主题的文章的其他参考。
【问题讨论】:
-
就个人而言,我认为它不会破坏封装。存在过度设计并使您的结构变得无用或笨重这样的事情。将图表与列表进行比较也不完全是 1 : 1。该列表隐藏了这些方面,因为它们是无用的或暴露出来的危险——用户不应该关心事物是如何被列出的,只要它们符合预期。给某人一个节点的引用是不好的;无法保证列表的有效性。
-
@ChiefTwoPencils 我喜欢你关于有用性的观点,但单独的声明对我来说还不够令人信服,尽管它已经非常有说服力了。我同意,我的 LinkedList 示例不是一个很好的示例。我应该给出一个更好的:考虑一些可以想象的约束最少的可扩展树。必须一直寻找同一个节点来修改它是相当不切实际的;我可以争辩说,它使客户端依赖于节点对象的使用来在图上进行操作;在我看来,封装也可以保护客户免受过多的数据结构知识
标签: java oop encapsulation object-oriented-analysis