直译为 不变性设计模式,也就是在对象被创建之后,状态不在发生变化,一旦被创建出来了,就不允许其被修改,保持了不变性的特性
在Java中,很多基本数据类型的包装类都用到了Immutability设计模式,例如Long Integer 甚至String,都具有不可变性,都是依靠了此种设计模式,在设计的时候已经遵守了不可变类的三点要求,类还有属性是final的,方法为只读的方法
像是String之中的replace方法,实现的方式都重新new一个String对象然后进行返回,并且对于这种采用了不可变设计模式的包装类中相关的修改操作,都会返回一个新的不可变对象,而且为了避免每次返回新的不可变对象,加入了享元模式来避免重复创建
对于享元模式的加入,就是利用其去减少创建对象的数量,从而减少内存的占用,享元模式本质上就是对象池,也就意味着这些不可变的对象在创建的时候,会先去享元对象池中查找一下,如果没有再进行创建
并且将新创建的对象放入对象池
在Java中,对这个设计模式进行了改进,像是Long,内部维护了一个静态对象池,存储了[-128,127]的数字,在jvm启动的时候进行了创建,而且对象池是不会改变的
那么,对于我们在实战中的Immutability模式,我们需要注意如下的设计
1.对象的所有属性都是final,包括属性中的对象
2.不可变对象需要正确发布
1.在Java中,由于可能在一个对象中拥有一个属性,这个属性也是一个对象,虽然对象本身是不可变的,但是属性中的对象可能不是不可变的,导致了隐含的并发问题,一定要在使用Immutability模式时候确保不变性的边界在哪里
2.看待如何正确发布不可变的对象,假设一个对象A本身是不可变的,对象B拥有对对象A的引用,虽然对象A是不可变的,但是对象B并不是原子性的,导致了对象A并不能保证可见性和原子性,对于这个问题,如果需要保证可见性,可以考虑加入volatile变量,如果需要保证原子性,可以考虑加入原子类来实现
比如利用 final AtomicReference 不可变的原子类来解决了原子性问题
对于一些不会发生改变的对象来说,优先考虑使用Immutability模式来进行解决实现
当然,如果可以的话,甚至可以考虑使用无状态来进行实现,无状态没有属性,只有方法,可以保证其的安全性