在阎宏博士的《JAVA与模式》一书中开头是这样描述不变(Immutable)模式的:

  一个对象的状态在对象被创建之后就不再变化,这就是所谓的不变模式。


不变模式的结构

  不变模式可增强对象的强壮型(robustness)。不变模式允许多个对象共享某一个对象,降低了对该对象进行并发访问时的同步化开销。如果需要修改一个不变对象的状态,那么就需要建立一个新的同类型对象,并在创建时将这个新的状态存储在新对象里。

  不变模式只涉及到一个类。一个类的内部状态创建后,在整个生命周期都不会发生变化时,这样的类称作不变类。这种使用不变类的做法叫做不变模式。不变模式有两种形式:一种是弱不变模式,另一种是强不变模式。

 弱不变模式

  一个类的实例的状态是不可改变的;但是这个类的子类的实例具有可能会变化的状态。这样的类符合弱不变模式的定义。要实现弱不变模式,一个类必须满足下面条件:

  第一、所考虑的对象没有任何方法会修改对象的状态;这样一来,当对象的构造函数将对象的状态初始化之后,对象的状态便不再改变。

  第二、所有属性都应当是私有的。不要声明任何的公开的属性,以防客户端对象直接修改任何的内部状态。

  第三、这个对象所引用到的其他对象如何是可变对象的话,必须设法限制外界对这些可变对象的访问,以防止外界修改这些对象。如何可能,应当尽量在不变对象内部初始化这些被引用的对象,而不要在客户端初始化,然后再传入到不变对象内部来。如果某个可变对象必须在客户端初始化,然后再传入到不变对象里的话,就应当考虑在不变对象初始化的时候,将这个可变对象复制一份,而不要使用原来的拷贝。

  弱不变模式的缺点是:

  第一、一个弱不变对象的子对象可以是可变对象;换言之,一个弱不变对象的子对象可能是可变的。

  第二、这个可变的子对象可能可以修改父对象的状态,从而可能会允许外界修改父对象的状态。

 强不变模式

  一个类的实例不会改变,同时它的子类的实例也具有不可变化的状态。这样的类符合强不变模式。要实现强不变模式,一个类必须首先满足弱不变模式所要求的所有条件,并且还有满足下面条件之一:

  第一、所考虑的类所有的方法都应当是final,这样这个类的子类不能够置换掉此类的方法。

  第二、这个类本身就是final的,那么这个类就不可能会有子类,从而也就不可能有被子类修改的问题。

 “不变"和"只读"的区别

  "不变"(Immutable)与"只读"(Read Only)是不同的。当一个变量是”只读“时,变量的值不能直接改变,但是可以在其他变量发生改变的时候发生改变。

  比如,一个人的出生年月日是”不变“属性,而一个人的年龄便是”只读“属性,不是”不变“属性。随着时间的变化,一个人的年龄会随之发生变化,而人的出生年月日则不会变化。这就是”不变“和“只读”的区别。

不变模式在JAVA中的应用

  不变模式在JAVA中最著名的应用便是java.lang.String类。String类是一个强不变类型,在出现如下的语句时:

        String a = "test";
String b = "test";
String c = "test";

  JAVA虚拟机其实只会创建这样一个字符串的实例,而这三个String对象都在共享这一个值。

不变模式的优点和缺点

  不变模式有很明显的优点:

  (1)因为不能修改一个不变对象的状态,所以可以避免由此引起的不必要的程序错误;换言之,一个不变的对象要比可变的对象更加容易维护。

  (2)因为没有任何一个线程能够修改不变对象的内部状态,一个不变对象自动就是线程安全的,这样就可以省掉处理同步化的开销。一个不变对象可以自由地被不同的客户端共享。

  不变模式的缺点:

  不变模式唯一的缺点是:一旦需要修改一个不变对象的状态,就只好创建一个新的同类对象。在需要频繁修改不变对象的环境里,会有大量的不变对象作为中间结果被创建出来,再被JAVA垃圾收集器收集走。这是一种资源上的浪费。

  在设计任何一个类的时候,应当慎重考虑其状态是否有需要变化的可能性。除非其状态有变化的必要,不然应当将它设计成不变类。

《JAVA与模式》之不变模式的更多相关文章

  1. <代码整洁之道>、<java与模式>、<head first设计模式>读书笔记集合

    一.前言                                                                                       几个月前的看书笔记 ...

  2. java Future模式

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  3. 《java与模式》

    2012年3月 随笔档案 - java_my_life - 博客园--此网友 12年的博客都是和模式有关的,希望可以多看看.http://www.cnblogs.com/java-my-life/ar ...

  4. java与模式读后总结

    一 老规则边看边写书上的代码,磨磨蹭蹭三个多星期终于把一本1000+的java与模式看完了. 于是,在这里贴上自己对每个模式的思考和总结,其实这个东西在我边看边写的时候已经写了一大半,博文再写一次算是 ...

  5. 《JAVA与模式》之观察者模式

    转自:http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html 在阎宏博士的<JAVA与模式>一书中开头是这样 ...

  6. JAVA的模式对话框和非模式对话框

    周末的时候,一位网友让我帮他把他的无模式对话框改成有模式对话框. 界面是由swing制作的,都是JFrame,我从来没有接触过swing编程.大致的代码还是看的懂,很多都和C#很相似. 然后就去查资料 ...

  7. java工厂模式

    (1)概念大白话:java工厂模式就是客户端(main函数)要创建对象觉得麻烦就让另外一个叫工厂的类帮它创建,然后自己每次要创建对象就叫工厂帮它弄,举个例子,在没有工厂这个"手下" ...

  8. 《JAVA与模式》之单例模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述单例模式的: 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的 ...

  9. Java代理模式

    java代理模式及动态代理类 1.      代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目 ...

随机推荐

  1. part1:6-Linux文本编辑器vi

    vi编辑器简介: vi是Linux系统的第一个全屏幕交互式编辑器:vim则是vi的升级版得到广大用户青睐. vim有三种工作模式:命令行模式.插入模式.底行模式 命令行模式常用功能键: yy:复制当前 ...

  2. Oracle连接字符串大全

    // 在 C# 代码中用以下数据库提供程序访问 Oracle 数据库 // Oracle Data Provider for .NET / ODP.NET 使用 TNS 写法 Data Source= ...

  3. ubuntu系统下安装pyspider:安装命令集合。

    本篇内容的前提是你已安装好python 3.5.在ubuntu系统中安装pyspider最大的困难是要依赖组件经常出错,特别是pycurl,但把对应的依赖组件安装好,简单了.下面直接上代码,所有的依赖 ...

  4. 原生js:click和onclick本质的区别

    原生javascript的click在w3c里边的阐述是DOM button对象,也是html DOM click() 方法,可模拟在按钮上的一次鼠标单击. button 对象代表 HTML 文档中的 ...

  5. 2018.10.01 bzoj3237: [Ahoi2013]连通图(cdq分治+并查集)

    传送门 cdq分治好题. 对于一条边,如果加上它刚好连通的话,那么删掉它会有两个大集合A,B.于是我们先将B中禁用的边连上,把A中禁用的边禁用,再递归处理A:然后把A中禁用的边连上,把B中禁用的边禁用 ...

  6. hdu-1143(简单dp)

    题目链接: 思路:利用前一个状态找到本次状态需要的次数,就是递推. 建立一个二维数组dp[i][j] ,i表示行,j表示多余的格子. 可以分为三种状态dp[i][0], dp[i][1] ,dp[i] ...

  7. IntelliJ IDEA 2017版 springloaded实现热部署

    1.配置pom.xml文档 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&qu ...

  8. VBA替换函数

    Sub test() On Error Resume Next Dim arr1, arr2, i, j arr1 = Range("T1:EI3") arr2 = Range(& ...

  9. Java Socket重要参数讲解

    (转自http://www.cnblogs.com/ggjucheng/archive/2012/01/06/2314679.html) ( http://docs.oracle.com/javase ...

  10. Resharper 修改命名空间

    1. 使用Reshared 右键->Refactor->Rename 修改所有文件的命名空间(鼠标移动到对应类的命名空间) 2.修改类库中的命名空间 包括程序集信息 右键->属性 3 ...