简体   繁体   English

可变类作为不可变类的子类

[英]Mutable class as a child of an immutable class

I want to have immutable Java objects like this (strongly simplified): 我希望有这样的不可变Java对象(强烈简化):

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. 虽然这在技术上很好,我想知道它是否符合OOP和继承,mutable也是类型不可变的。 I want to avoid the OOP crime to throw UnsupportedOperationException for immutable object, like the Java collections API does. 我想避免OOP犯罪为不可变对象抛出UnsupportedOperationException ,就像Java collections API那样。

What do you think? 你怎么看? Any other ideas? 还有其他想法吗?

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". Joda Time使用“ReadableXXX”来表示“此类仅提供读访问权限;其他子类可能是可变的”。 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. 基本上问题在于表达否定 - Immutable描述你不能做什么(改变它)并且不能在子类中明智地强制执行。 (Even if the fields within Immutable were final, it wouldn't stop a subclass having its own mutable fields.) (即使Immutable中的字段是最终的,它也不会阻止具有自己的可变字段的子类。)

I would suggest that you should have an inheritable base "ReadableFoo" class, a derived sealed ImmutableFoo class, and other derived MutableFoo classes. 我建议你应该有一个可继承的基础“ReadableFoo”类,一个派生的密封ImmutableFoo类,以及其他派生的MutableFoo类。 Code which doesn't care whether a Foo is mutable or not can accept a ReadableFoo. 不关心Foo是否可变的代码可以接受ReadableFoo。 Code that wants a Foo that is guaranteed not to change can accept an ImmutableFoo. 想要保证不会改变的Foo的代码可以接受ImmutableFoo。 Code which can need to change a Foo can accept a MutableFoo. 需要更改Foo的代码可以接受MutableFoo。

Note that the constructors for both ImmutableFoo and MutableFoo should typically accept a ReadableFoo. 请注意,ImmutableFoo和MutableFoo的构造函数通常应该接受ReadableFoo。 That way, any Foo will be convertible to a mutable or immutable version. 这样,任何Foo都可以转换为可变或不可变的版本。

Immutable classes should be final precisely to avoid mutable sub-types. 不可变类应该是final以避免可变子类型。

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. 在Java允许你这样做的意义上它可能是合法的(在语言中不强制实现不变性),但只要它可以被分类,这样的类就不是真正不可变的。

This is why String is final. 这就是String是最终的原因。

Your subclass is bad because it violates the Liskov substitution principle . 您的子类很糟糕,因为它违反了Liskov替换原则 Don't do it. 不要这样做。

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. 为了实现这样的不可变行为,我宁愿依赖一个Immutable接口,只提供getter方法,而对象包含两者。 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). 但通常情况下,依靠其他开发者的善意是让他们对错误负责的一种甜蜜方式(比如将不可变的东西变成可变的)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM