Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>You provide an <code>interface</code> that has no mutation methods. Then, you provide mutable implementations that are only known to the creator.</p> <pre><code>public interface Person { String getName(); } public class MutablePerson implements Person { private String name; public MutablePerson(String name) { this.name = name; } @Override public String getName() { return name; } public void setName(String name) { this.name = name; } } </code></pre> <p>At this point, if you return <code>Person</code> objects everywhere, the only way for someone to modify the returned object is to cheat and cast it back to a <code>MutablePerson</code>. In effect, the mutable objects become immutable unless the code is a complete hack.</p> <pre><code>Person person = new MutablePerson("picky"); // someone is cheating: MutablePerson mutableAgain = (MutablePerson)person; mutableAgain.setName("Phoenix"); // person.getName().equals("Phoenix") == true </code></pre> <p>When not dealing with a bunch of younger programmers that will notice the true implementation is mutable, and thus they can cast it to change it, then you provide the safety of immutability with the benefit of being able to put it together without an endless constructor, or using a Builder (in effect, the mutable version is the Builder). A good way to avoid developers abusing the mutable version is to leave the mutable version as package private so that only the package knows about it. The negative of that idea is that this only works if it will be instantiated in the same package, which may be the case, but it obviously may not be the case in situations such as where DAO's are used with multiple package-defined implementations (e.g., MySQL, Oracle, Hibernate, Cassandra, etc., all returning the same stuff, and hopefully separated from each other to avoid cluttering their packages).</p> <p>The real key here is that people should never build up from the Mutable objects except to implement further-down interfaces. If you're extending, and then returning an immutable subclass, then it's not immutable if it exposes a mutable object, by definition. For example:</p> <pre><code>public interface MyType&lt;T&gt; { T getSomething(); } public class MyTypeImpl&lt;T&gt; implements MyType&lt;T&gt; { private T something; public MyTypeImpl(T something) { this.something = something; } @Override public T getSomething() { return something; } public void setSomething(T something) { this.something = something; } } public interface MyExtendedType&lt;T&gt; extends MyType&lt;T&gt; { T getMore(); } public class MyExtendedTypeImpl&lt;T&gt; extends MyTypeImpl&lt;T&gt; implements MyExtendedType&lt;T&gt; { private T more; public MyExtendedTypeImpl(T something, T more) { super(something); this.more = more; } @Override public T getMore() { return more; } public void setMore(T more) { this.more = more; } } </code></pre> <p>This is honestly the way that <code>Collection</code>s in Java should have been implemented. A readonly interface could have taken the place of the <code>Collections.unmodifiable</code> implementations, thus not having people unexpectedly using immutable versions of mutable objects. In other words, you should never hide immutability, but you can hide mutability.</p> <p>Then, they could sprinkle immutable instances that truly can't be modified, and that would keep developers honest. Similarly, I would likely expect to see an immutable version of the above interface somewhere (with better names):</p> <pre><code>public class MyTypeImmutable&lt;T&gt; implements MyType&lt;T&gt; { private final T something; public MyTypeImmutable(T something) { this.something = something; } @Override public T getSomething() { return something; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload