现在的位置: 首页 > 综合 > 正文

Java 不变模式

2013年09月09日 ⁄ 综合 ⁄ 共 2658字 ⁄ 字号 评论关闭

题记:上邪 我欲与君相知 长命无绝衰 山无陵 江水为竭 冬雷阵阵 夏雨雪 天地合 乃敢与君绝

 

从String说起:

用Java或C#时,如果一个字符串是频繁变化的,是不建议把该变量设为String类型的,而建议为StringBuilder,经过N次变化得到最终的字符串后,再把StringBuilder转化为String交给某个方法去处理。

不变模式会告诉我们,这是为什么?

备注:

我学习设计模式时基本都参考阎宏的《Java与模式》一书,该书中讲述不变模式举String这个例子时,若字符串频繁变化时建议使用StringBuffer,我原来用C#写代码时习惯用StringBuilder,.netframework只保证StringBuilder的公共Static成员是线程安全的。于是我去查看Java中StringBuilder的原码发现该类的注释中有这么一句:

Where possible, it isrecommended that this class be used in preference to StringBuffer as it will befaster under most implementations.

请注意 “where possible”,的意思是:在单线程情况下。而StringBuffer是线程安全的。

 

不变模式的概念:

 

一个对象如果可以改变自身的状态,我们说它是可变的;如果一个对象的状态自创建起便不可改变,我们说它是不可变的。

不变模式只涉及到一个类,这个类的内部状态创建以后,在整个生命周期都不会发生变化,这样的类叫做不变类,这种使用不变类的做法叫做不变模式。不变模式只有一个类,所以不需要类图来表示。

备注:什么是内部状态?

在书上看,第一眼挺晕的,因为搞学术的都有这“毛病”,喜欢把简单的东西说的很复杂,你看那些博士论文,还有一些很牛B的硕士论文就会发现这个问题。我只所以把“毛病”加引号是因为我不全盘否定这种做法,虽然他对初学者及搞应用的人来讲会造成一定的障碍,但它对理论的发展却很重要,因为我们理解这个概念以后,讨论起来就会更加清晰,就像无论我们学什么,讲什么第一步总是要先把概念讲清楚,理解清楚。如果缺了这一步,费半天劲会发现不知道自己在干什么,这个太可怕了。

言归正传,所谓内部状态,就是这个类的属性,完了。就像WebService,一听好神奇啊,你去看书,那理论一套一套的好几章,说白了就是:基于Web的API,完了。

怎么让它不变:

使用不变类的做法就是不变模式,所谓不变类就是它的整个生命周期里它的状态就不会改变,那怎样让它的状态(属性)不会发生变化呢?当我们把概念讲到这里的时候,我想我们基本都会把它写出来了:把属性设为私有,只给Geter不给Setter就OK了。Yes!给个例子先:

 public class PartySchool {

    private String appearance;
 
    public String getAppearance() {
       return appearance;
    }
    public PartySchool(String appearance)
    {
       this.appearance = appearance;
    }
}

CodeIP-1

当客户端调用的时候给予初始值:

PartySchool ps = newPartySchool(“handsome”);

那么在PartySchool的整个生命周期里一直都handsome,是不可变的。

特殊情况:

我家养了一条狗叫毛毛,给毛毛建个类先:

public class Dog {
    private String name;
 
    public String getName() {
       return name;
    }
 
    public void setName(String name) {
       this.name = name;
    }
    public Dog(String name)
    {
       this.name = name;
    }
}

CodeIP-2

显然,我们家毛毛的名字是可以改的,比如我不叫它毛毛了给它取个英文名字叫Douglas。

顺便把PartySchool这个类也修改下:

public class PartySchool {
    private String appearance;
    private Dog dog;
    public String getAppearance() {
       return appearance;
    }
    public Dog getDog() {
       return dog;
    }
 
    public PartySchool(String appearance,Dog dog)
    {
       this.appearance = appearance;
       this.dog = dog;
    }
}

CodeIP-3

我想看到这个类会隐隐有种不详的预感,写个测试验证一下:

public static void main(String[] args) {
       Dog dog = new Dog("maomao");
       PartySchool ps = new PartySchool("handsome", dog);
       System.out.println(ps.getAppearance());
       System.out.println(ps.getDog().getName());
       System.out.println("-----------------Changed--------------------");
       dog.setName("Douglas");
       System.out.println(ps.getAppearance());
       System.out.println(ps.getDog().getName());
    }

CodeIP-4

悲剧的结果:

handsome

maomao

-----------------Changed--------------------

handsome

Douglas

悲剧发生了,因为不变类里出现了可变的不和谐分子。如何把它和谐掉呢?伟大的程序员是不需要维稳经费的,我们只需要改掉一行代码就OK了。

把PartySchool的构造函数改为:

   public PartySchool(String appearance,Dog dog)
    {
       this.appearance = appearance;
       Dog dogClone = new Dog(dog.getName());
       this.dog = dogClone;
    }

CodeIP-5

同样的测试用例测试结果:

handsome

maomao

-----------------Changed--------------------

handsome

maomao

抱歉!评论已关闭.