
5.12 构造方法私有化
每一个类中都一定会存在有至少一个构造方法,并且构造方法是产生实例化对象的主要支持。然而构造方法本身也属于方法,那么方法也可以利用private来实现封装,本节将为读者通过构造方法的封装讲解单例设计模式(Singleton)的基础实现。
5.12.1 问题的引出
类的封装性不光体现在对属性的封装上,实际上方法也是可以被封装的,当然,在方法封装中也包含了对构造方法的封装。如以下代码,就是对构造方法进行了封装。
【例5.62】构造方法的封装

从之前讲解过的知识中可以清楚地知道,一个类要想使用,则必须有实例化对象的产生,而且现在要是想调用Singleton类中的print()方法,则一定要首先产生Singleton的实例化对象,但是由于此时构造方法被私有化了,所以如果按照如下的程序编写,则肯定会出现错误。
【例5.63】错误的代码,直接实例化Singleton类对象

程序执行结果:

从以上的错误提示中可以发现,程序是在使用new关键字实例化对象的时候出现了错误,而对于声明对象则没有任何的错误。那么该如何解决以上的问题呢?
封装是指一切都外部不可见,那么就意味着在外部根本就无法调用被封装的构造方法,既然外部不能调用,那么在内部呢?
【例5.64】在内部产生Singleton的对象

上面的程序编译后,并不会产生任何的问题,此时的重点在于如何能够将内部的instance对象传递到类的外部去,这样外部就可以通过instance来实例化其他的Singleton的对象了。那么对象到底该如何取呢?下面对之前学习过的知识作进一步的分析。
5.12.2 问题的解决
学习static时曾经讲过,static类型的属性可以由类名称直接调用,并且不受到类实例化对象的限制。所以此时可以将instance属性声明为static类型,这样就可以通过类名称直接调用。
【例5.65】将instance声明为static类型

程序执行结果:

由运行结果可以发现,程序成功地取得了Singleton的实例化对象并调用了里面的print()方法,但是这样做本身也存在着问题,因为类中的属性必须封装,所以此处应该将instance属性进行封装,而封装之后必须通过方法取得,但因为instance属性属于静态属性,所以此处必须声明一个静态方法,这样就可以被类名称直接调用。
【例5.66】声明静态方法,取得Singleton类的实例

程序执行结果:

5.12.3 程序的意义
从上面的程序中可以发现虽然声明了3个Singleton的对象,但是实际上所有的对象都只使用了instance一个引用,也就是说,此时不管外面如何使用,最终结果也只是有一个实例化对象存在,如图5-22所示。

图5-22 不管有多少个对象,实际上都只有一个实例
在设计模式中将这样的设计称为单例设计模式(Singleton),即无论程序怎样运行,Singleton类永远只会有一个实例化对象存在。
提示
单态的应用
实际上这样的应用,读者应该早就能有所了解了,读者应该都很清楚在windows中有一个回收站的程序,除了桌面上的回收站之外,每个硬盘上都有一个回收站,实际上每个硬盘的回收站和桌面上的回收站都是同一个,那么也就是说在整个操作系统上只有一个回收站实例,各个地方只是引用此实例而已。
在此读者只需要记住,只要将构造方法私有化了,就可以控制实例化对象的产生了,在后面讲解类库的时候,会出现单例模式在Java中的一些应用。