Mutable class as a child of an immutable class

大城市里の小女人 提交于 2020-07-05 02:35:33

问题


I want to have immutable Java objects like this (strongly simplified):

class Immutable {

    protected String name;

    public Immutable(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

In some cases the object should not only be readable but mutable, so I could add mutability through inheritance:

public class Mutable extends Immutable {

    public Mutable(String name) {
        super(name);
    }

    public void setName(String name) {
        super.name = name;
    }

}

While this is technically fine, I wonder if it conforms with OOP and inheritance that mutable is also of type immutable. I want to avoid the OOP crime to throw UnsupportedOperationException for immutable object, like the Java collections API does.

What do you think? Any other ideas?


回答1:


Avoid calling the parent "Immutable" because it becomes a lie in the child class - if you do want to make a class immutable, it should be final too in order to prevent exactly this problem.

Joda Time uses "ReadableXXX" to give the idea that "this class only provides read access; other subclasses may be mutable". I'm not sure whether I like that idea, but I can't say I've seen many alternatives.

Basically the problem is with expressing a negative - Immutable describes what you can't do (mutate it) and that can't be sensibly enforced in subclasses. (Even if the fields within Immutable were final, it wouldn't stop a subclass having its own mutable fields.)




回答2:


Your subclass is bad because it violates the Liskov substitution principle. Don't do it.




回答3:


I would suggest that you should have an inheritable base "ReadableFoo" class, a derived sealed ImmutableFoo class, and other derived MutableFoo classes. Code which doesn't care whether a Foo is mutable or not can accept a ReadableFoo. Code that wants a Foo that is guaranteed not to change can accept an ImmutableFoo. Code which can need to change a Foo can accept a MutableFoo.

Note that the constructors for both ImmutableFoo and MutableFoo should typically accept a ReadableFoo. That way, any Foo will be convertible to a mutable or immutable version.




回答4:


Immutable classes should be final precisely to avoid mutable sub-types.

Allowing a sub-type of an immutable class to break the immutable contract makes it rather pointless to have the class be immutable in the first place. It may be legal in the sense that Java allows you to do it (immutability is not enforced in the language) but such a class isn't truly immutable as long as it can be sub-classed.

This is why String is final.




回答5:


I find your code rather curious.

To implement such an Immutable behaviour, I would rather has relied upon an Immutable interface, providing only the getter method, whiile the object contains both. This way, operations relying on the immutable objects would have called the interface, while others would have called the object.

And, if you really don't want your immutable objects to be casted as mutable ones, you can then use proxies, and all the enterprise tools (aspects, and so on). But usually, relying upon other developpers' goodwill is a sweet way to make them responsible of their mistakes (like casting the immutable in mutable).



来源:https://stackoverflow.com/questions/2493891/mutable-class-as-a-child-of-an-immutable-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!