Search code examples
javaoopencapsulationobject-oriented-analysis

To what degree does this Design violate Encapsulation


I am designing a graph object in Java. Me being the designer I doubt that this design violates encapsulation but I would like some insight from others.

Down below, we have the two interfaces Graph and Vertex.

Graph implementations are responsible for managing vertices in the graph, which consists of there creation, removal, ensuring imposed constraints, etc. The generic parameters stand for Type, the type of the values stored in a vertex, and Weight which is the type of the weights stored in edges:

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

The Vertex interface is used for getting and modifying properties of a vertex and also to keep a reference; its implementation is determined by the implementation of the graph - the client does not know anything about its internal implementation. It could look like this:

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
}

The reason I use a vertex interface is so that the client can simply keep a reference to the vertex in question and pass the reference to the graph. I could also have a graph interface like this:

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

In this graph interface the 'modify' method would always have to search for the vertex; this would be very impractical especially when we want to modify the same vertex often - instead the client can just keep a reference pass that like in the first approach.

To come to my question, I am very strict with encapsulation, does this violate the principles of encapsulation?

Personally, I do not think it would violate encapsulation because the client does not know what is performed internally by the the graph object nor by the vertex. However, we do leak the information that the graph uses vertices somehow (though the exact internal structure is not exposed) which is not done is other libraries. Examples might be data structures which are subsets of Graphs, such as Trees and LinkedLists: the LinkedList implementation in the core Java libraries does not let the application notice that some Node interface is utilised; tree implementations which I have seen in various other libraries do not expose their Nodes either.

So under strict object oriented terms, does this design violate encapsulation, or does it not? Additional references to existing object-oriented libraries, also outside the spectrum of Java, or articles discussing this topic, I would also welcome.


Solution

  • I think this is similar to Map interface exposing Map.Entry. The concept of graph presupposes the concept of vertex - you can't have one without the other. It is thus completely legitimate to expose both.

    On the other hand, you're exposing (or may be limiting) at least some implementation details here. Your

    void modify(T vertex);
    

    in Graph assumes that vetexes are addressable by their contents. That may not always be the case. I think this is too much of a restriction on T.

    I'd say that, to ensure encapsulation, the only interrogation operation on the graph itself should be Set<Vertex<T>> getVertices. The rest should be on the vertex.

    Creation operation should return the entity it creates:

    Vertex<T> createVertex(T value)
    

    You can then add Graph.createEdge(Vertex<T> v1, Vertex<T> v2) and removeEdge(Vertex<T> v1, Vertex<T> v2).