java设计模式之单例模式

来源:互联网 发布:java编程计算n的阶乘 编辑:程序博客网 时间:2024/06/06 01:46
          一直以来都是看同行的博客或技术论坛,一遇到自己不知道的问题就回去百度,google,总之最后大部分都会解决。万事开头难,一直有心去写技术博客,但从来没有写过,写博客一方面有助于自己学习一些知识点和把自己对知识点的理解表达出来,今天就从最简单设计模式之单例模式入手,写第一篇博客。

1.什么是单例模式

        单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并提供全局访问点。

2.单例的使用

        

        典型的代码是:


但常常我们还要面对更复杂的现实问题。其他博主中也写道单例分为懒汉和饿汉的模式。

2.1.全部使用静态成员

        有时我们会看到一个Singleton的成员变量全部是static类型的,这种情况下,建议直接删除构造方法和静态工厂方法,直接作为一个工具类就好了。因为这个类已经不需要对象了,何必多此一举呢?

2.2.对构造方法不进行私有化处理

        构造方法不进行私有化,就意味着client可以自由的通过new Singleton()构造新的实例,这已经有违了采用单例模式的本意,不如把静态工厂方法删掉吧,放弃单例的需求。如果有理由让一个类既可以是单例,也可以是多例,我想应该仔细设计了。

2.3.静态工厂方法需要参数

        我们时常会看到这样的构造方法:

        public static Singleton getInstance(Context context)

        如果一个实例的构造需要参数,那么就意味着传递不同的参数将影响到单例的状态。比如我们看这样一段代码。





        在程序中的某处调用时使用了Singleton.getInstance(objA).fun();另一处使用了Singleton.getInstance(objB).fun();显然,同样一个Singleton实例,在运行时出现了未预期的行为。这与设计单例时我们期望的可控性是不符的,你无法预知在下一次使用value时真正的行为。

2.4.派生子类

        如果需要在继承树中使用单例,只要将基类的构造函数由private调整为protected即可,但问题会很多,这个有很多文章来讨论了,在此略过。

        简而言之,如果在基类中实现静态工厂方法,必然会与子类产生依赖,即发生父类依赖于子类的非正常情况。如果在子类中实现静态工厂方法,则整个设计就出现了父类无法约束子类的创建情况,也就是说可能出现违背设计意图的实现。建议对单例类不要再派生。

2.5.多线程问题

        既然在软件运行期内只有一个实例,由于无法限制client的调用时机,就不可避免要处理互斥问题。

        先来看静态工厂方法的互斥处理,典型的代码是:





        这段代码既完成了在构造这个唯一实例时的保护,又在构造完以后的多次获取实例时不做无谓的互斥处理以提高运行效率,是目前比较推荐的实现方法。

        再来看类的其他成员的互斥问题,这个就与其他class是一样的了,需要小心的处理多线程访问的影响。


2.6 在一个进程中会同时出现多个单例吗

        在分布式系统、多个类加载器、以及序列化的的情况下,会产生多个单例,这一点是无庸置疑的。什么情况下使用单例提供的getInstance()方法只能得到同一个单例,除非是使用反射方式,将会得到新的单例。代码如下



这样,每次运行都会产生新的单例对象。所以运用单例模式时,一定注意不要使用反射产生新的单例对象。

2.7.内存回收

        单例的内存问题也是值得关注的,一量单例创建以后,静态变量instance就会持有一份内存引用,而且由于其static性质,这份内存将在程序运行期间持续占用,无法通过GC进行回收。所以对内存敏感的程序要减少对单例的使用,或者妥善处理内存回收问题。


0 0