Search code examples
javaencapsulation

If encapsulation is properly designed in the class


Is encapsulation is properly designed in this class? Example object instances with negative height and width values can or cannot exist?

import java.awt.Dimension; 
/** * Example class. The x and y values should never * be negative. 
*/ 
public class Example { 
    private Dimension d = new Dimension (0, 0); 
    public Example () {} 
    /** * Set height and width. Both height and width must be nonnegative * or an exception is thrown. */ 
    public synchronized void setValues (int height, int width) throws IllegalArgumentException { 
        if (height < 0 || width < 0) throw new IllegalArgumentException(); 
        d.height = height; 
        d.width = width; 
    }

    public synchronized Dimension getValues() { // Passing member content by ref
        return d; 
    }
}

Solution

  • You can't enforce that. People can still alter the height and width values via the Dimension object you return in getValues() even though that violates the law of demeter principle.

    Example example = new Example();
    example.setValues(10, 5);
    System.out.println(example.getValues()); // java.awt.Dimension[width=5,height=10]
    
    Dimension dimension = example.getValues();
    dimension.height = -1;
    dimension.width = -1;
    System.out.println(example.getValues()); // java.awt.Dimension[width=-1,height=-1]
    

    From the docs: https://docs.oracle.com/javase/8/docs/api/java/awt/Dimension.html#width

    public int width

    The width dimension; negative values can be used.

    To overcome this a solution could be to return a deep clone of the Dimension object in getValues() to prevent changes to the original object using a library such as: https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/SerializationUtils.html#clone(java.io.Serializable)

    public synchronized Dimension getValues() { 
        return SerializationUtils.clone(d); 
        // OR return new Dimension(d.width, d.height);
    }