有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java这种设计在多大程度上违反了封装

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

下面是图形和顶点的两个接口

图形实现负责管理图形中的顶点,包括创建、删除、确保施加的约束等。通用参数表示Type,即存储在顶点中的值的类型,以及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...
}

顶点接口用于获取和修改顶点的属性,还用于保留引用;它的实现由图的实现决定——客户机对其内部实现一无所知。它可能是这样的:

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

在这个图形界面中,“修改”方法总是要搜索顶点;这将是非常不切实际的,尤其是当我们想要经常修改同一个顶点时——相反,客户机可以像第一种方法那样只保留一个引用过程

说到我的问题,我对封装非常严格,这是否违反了封装的原则

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

因此,在严格的面向对象术语下,这种设计是否违反了封装?我也欢迎对现有的面向对象库(也在Java范围之外)的其他参考,或讨论此主题的文章


共 (2) 个答案

  1. # 1 楼答案

    我认为这类似于地图界面。进入图的概念以顶点的概念为前提——你不能没有一个顶点而没有另一个顶点。因此,将两者都揭露出来是完全合法的

    另一方面,您在这里公开(或可能限制)了至少一些实现细节。你的

    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)

  2. # 2 楼答案

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

    破坏封装是指以不安全的方式暴露内部,例如返回一个可变集合(例如List<Vertex<T>>),它是一个内部数据结构,而不是通过更受控的API(例如add(Vertex<T>))来保护它。如果你失去了对内脏的控制,整个世界都可以玩你的私处,你对此无能为力

    例如,一些Map接口公开了一个表示键或值的集合,并将这些实现与映射本身支持的突变联系起来。这是一种既安全又方便的暴露方式

    考虑不要公开像内部数据结构、布尔或位标志之类的东西(也许在API中使用枚举或接口,内部需要更有效的东西)或者具有复杂操作顺序的突变,例如“先调用init,然后调用setup,然后调用xyz,然后确保dispose”。这类东西你想通过方便的结构和常见的设计模式嵌入到你的API中