第二篇 创建对象
创建一个对象并不难,但当我们不得不为每新添一种新的接口实现或者抽象类的具体子类而到处修改客户代码时,就不得不思考直接使用new创建对象所带来的高耦合问题。
我们知道,如果类之间耦合度高,那么一个类里的一小处变化都可能导致其他类都发生未知的变化,这样的程序本身就充满了“腐臭”的气味,是不易重用的、脆弱的。OOP带给我们的好处之一是封装,如果封装这些实例化的细节,即对客户对象隐藏实例化的过程,那么我们新添一个接口的实现或者抽象类的具体类,也不会影响客户代码了,这样就降低了耦合度。
创建类型的模式把使用对象和实例化对象进行了分离,本篇我们将讲述如何实例化对象,而不会引起客户对象和服务对象之间高耦合的问题,这在提高代码的可移植性、可重用性和方便单元测试等方面都具有重要意义。
第3章:单例(Singleton)模式
我们在一个系统里经常使用到单例对象,这一章将讲述如何保证一个类在系统里只有一个对象被实例化。
第4章:工厂方法(Factory Method)模式
讲述如何实例化对象使得对象和使用者之间的耦合度降低。
第5章:原型(Prototype)模式
这一章将讲述如何通过复制现有的对象快速地创建一个新的复杂对象。
第6章:控制反转(IoC)
我们介绍了时下最流行的两个概念,控制反转(IoC)和注入依赖(DI)。很多人对控制反转和注入依赖在概念上混为一谈,这一章将为读者讲述它们二者之间的关系,并介绍目前关于二者的一些常用技术和框架。
第3章 单例(Singleton)模式
如果要保证系统里一个类最多只能存在一个实例时,我们就需要单例模式。这种情况在应用中经常碰到,例如缓存池、数据库连接池、线程池、一些应用服务实例等。在多线程环境中,为了保证实例的唯一性其实并不简单,本章将和读者一起探讨如何实现单例模式。
本章将介绍单例模式,内容包括:
最简单的单例模式。
如何创建并发访问效率高的单例。
单例模式序列化应该注意的问题。
3.1 最简单的单例
为了限制该类的对象被随意地创建,需要保证该类构造方法是私有的,这样外部类就无法创建该类型的对象了;另外,为了方便给客户对象提供对此单例对象的使用,我们为它提供一个全局访问点,代码如下所示。
代码注解
Singleton类只有一个构造方法,它是被private修饰的,客户对象无法创建该类实例。
我们为此单例实现的全局访问点是public static Singleton getInstance()方法。
注意:instance变量是私有的,外界无法访问。
读者还可以定义instance变量是public的,这样把属性直接暴露给其他对象,就没必要实现public static Singleton getInstance()方法,但是可读性没有方法来的直接,而且把该实例变量的名字直接暴露给客户程序,会增加代码的耦合度,如果改变此变量名称,会引起客户类的改变。
还有一点,如果该实例需要比较复杂的初始化过程时,把这个过程应该写在static{……}代码块中。
此实现是线程安全的,当多个线程同时去访问该类的getInstance()方法时,不会初始化多个不同的对象,这是因为,JVM(Java Virtual Machine)在加载此类时,对于static属性的初始化只能由一个线程执行且仅一次[1]。
由于此单例提供了静态的公有方法,那么客户使用单例模式的代码也就非常简单了,如下所示。
Singleton singleton=Singleton. getInstance();
[1] Static属性和Static初始化块(Static Initializers)的初始化过程是串行的,这个由JLS(Java Language Specification)保证,参见James Gosling, Bill Joy, Guy Steele and Gilad Bracha编写的“The Java™ Language Specification Third Edition”一书的12.4节。