该设计在多大程度上违反了封装

时间:2015-08-11 18:52:48

标签: java oop encapsulation object-oriented-analysis

我正在用Java设计图形对象。我是设计师,我怀疑这个设计是否违反了封装,但我希望得到其他人的一些见解。

在下面,我们有两个接口Graph和Vertex。

图形实现负责管理图形中的顶点,其中包括创建,删除,确保强制约束等。通用参数代表 T ype,存储的值的类型一个顶点, W 八,这是存储在边缘的权重类型:

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...
}

在此图表界面中,修改&#39;方法总是要搜索顶点;这将是非常不切实际的,特别是当我们想要经常修改相同的顶点时 - 相反,客户端可以保持像第一种方法中那样的引用传递。

为了解决我的问题,我对封装非常严格,这是否违反了封装原则?

就个人而言,我认为它不会违反封装,因为客户端不知道图形对象内部还是顶点执行的内容。但是,我们确实泄漏了图形以某种方式使用顶点的信息(尽管未公开精确内部结构),其他库未执行此操作。示例可能是作为Graph的子集的数据结构,例如Trees和LinkedLists:核心Java库中的LinkedList实现不会让应用程序注意到使用了某个Node接口;我在各种其他库中看到的树实现也没有公开它们的节点。

因此,在严格的面向对象的条款下,这种设计是否违反封装,或者不是?我还欢迎对现有面向对象库的其他参考,也不包括Java的范围,或讨论该主题的文章。

2 个答案:

答案 0 :(得分:1)

我认为这类似于Map接口公开Map.Entry。图的概念预先假定了顶点的概念 - 你不能拥有顶点的概念。因此,揭露两者是完全合法的。

另一方面,您在这里暴露(或可能限制)至少一些实施细节。你的

void modify(T vertex);
Graph中的

假设vetex可以通过其内容进行寻址。情况可能并非总是如此。我认为这对T来说太过限制了。

我要说,为了确保封装,图表本身唯一的询问操作应该是Set<Vertex<T>> getVertices。其余的应该在顶点上。

创建操作应该返回它创建的实体:

Vertex<T> createVertex(T value)

然后,您可以添加Graph.createEdge(Vertex<T> v1, Vertex<T> v2)removeEdge(Vertex<T> v1, Vertex<T> v2)

答案 1 :(得分:-1)

我认为它不违反封装。图形的目的通常是管理顶点和边缘,因此将这些概念作为类型公开和使用非常有意义。在您的问题中,您引用LinkedList,但其主要目的是成为List而不是暴露于节点的数据结构。尽管大多数客户应该只使用其List API,但它可以完美地安全地公开其节点。

打破封装是指以不安全的方式暴露内部的行,例如返回一个可变集合(例如List<Vertex<T>>),这是一个内部数据结构,而不是通过更受控制的API保护它(例如{ {1}}等)。如果你已经失去对内脏的控制权,那么整个世界都可以和你的私人一起玩,你几乎无能为力。

一些add(Vertex<T>)接口例如公开表示键或值的集合,并将这些实现与地图本身支持以进行突变。这是安全而又方便的曝光。

考虑不要公开内部数据结构,布尔或按位标志(可能在API中使用枚举或接口以及内部需要更高效的内容),或者具有棘手操作顺序的变更器,例如&#34;第一次调用Map,然后致电init,然后致电setupxy,然后确保z&#34;。你希望通过便利结构和通用设计模式将这种东西烘焙到你的API中。