单例模式
构造方法私有,不允许外部直接创建对象
饿汉模式
创建私有静态类的实例:因为构造私有,静态的话使用类就能得到,这个就能从通过方法获得实例
因为实例被设置为静态,类在加载时就被创建,不管用户是不是要调用
懒汉模式
|
|
这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
为了提高性能,需要使用双重锁检查DCL,即 double-checked locking
使用volatile关键字是防止DCL失效
内部类
|
|
这种方式能达到双检锁方式一样的功效,但实现更简单。
对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
这种方式同样利用了 classloder 机制来保证初始化 instance 时只有一个线程,它跟饿汉不同的是:
饿汉方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),
而这种方式是 Singleton 类被装载了,instance 不一定被初始化。
因为 SingletonHolder 类没有被主动使用,只有显示通过调用 getInstance 方法时,才会显示装载 SingletonHolder 类,从而实例化 instance。
想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比饿汉方式就显得很合理。
枚举
|
|
这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
不能通过 reflection attack 来调用私有构造方法。
http://www.runoob.com/design-pattern/singleton-pattern.html
破坏单例
反射
|
|
http://iamzhongyong.iteye.com/blog/2053010
序列化
序列化单例后再反序列化回来会破坏单例,可以重写readResolve方法
类加载
两个不同的类加载器,加载单例会产生两个不一样的单例
http://javarevisited.blogspot.com/2011/03/10-interview-questions-on-singleton.html
http://stackoverflow.com/questions/11654876/cracking-singleton-with-other-ways
工厂模式
概念
- 使用工厂方法代替
new操作 - 工厂模式包括
工厂方法模式和抽象工厂模式 抽象工厂模式是工厂方法模式的扩展
意图
- 定义一个接口老创建对象,但是让子类来决定哪些类需要被实例化
- 工厂发放把实例化的工作推迟到子类中去实现
使用场景
- 有一组类似的对象需要创建
- 在编码时不能预见需要创建哪种类的实例(超市里买苹果,不知道买蛇果,阿克苏还是冰糖心)
- 系统需要考虑扩展性
常见应用
jdbc
执行sql的java api,可以为多种数据库提供统一访问spring Bean Factory
Bean Factory 是spring中IoC的基本容器,是一个产生bean给客户端的工厂
对比
- 工厂模式是一种极段的抽象工厂模式,而抽象工厂模式是工厂模式的推广
- 工厂模式用来创建一个产品的等级结构,而抽象工厂模式用来创建多个产品的等级结构
- 工厂模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类
抽象工程关键在于产品之间的抽象关系,所以至少要两个产品;工厂方法在于生成产品,不关注产品间的关系,所以可以只生成一个产品。
抽象工厂中客户端把产品的抽象关系理清楚,在最终使用的时候,一般使用客户端(和其接口),产品之间的关系是被封装固定的;而工厂方法是在最终使用的时候,使用产品本身(和其接口)。
抽象工厂的工厂是类;工厂方法的工厂是方法。
工厂方法模式: 一个抽象产品类,可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。 每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式: 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。 每个具体工厂类可以创建多个具体产品类的实例。
区别: 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个