java

位置:IT落伍者 >> java >> 浏览文章

Java模式设计之单例模式(二)


发布日期:2020年01月16日
 
Java模式设计之单例模式(二)

在什么情况下使用单例模式

使用单例模式的条件

使用单例模式有一个很重要的必要条件

在一个系统要求一个类只有一个实例时才应当使用单例模式反过来说如果一个类可以有几个实例共存那么就没有必要使用单例类但是有经验的读者可能会看到很多不当地使用单例模式的例子可见做到上面这一点并不容易下面就是一些这样的情况

例子一

我的一个系统需要一些全程变量学习了单例模式后我发现可以使用一个单例类盛放所有的全程变量请问这样做对吗?

这样做是违背单例模式的用意的单例模式只应当在有真正的单一实例的需求时才可使用

一个设计得当的系统不应当有所谓的全程变量这些变量应当放到它们所描述的实体所对应的类中去将这些变量从它们所描述的实体类中抽出来 放到一个不相干的单例类中去会使得这些变量产生错误的依赖关系和耦合关系

例子二

我的一个系统需要管理与数据库的连接学习了单例模式后我发现可以使用一个单例类包装一个Connection 对象并在finalize()方法中关闭这个Connection 对象这样的话在这个单例类的实例没有被人引用时这个finalize() 对象就会被调用因此Connection 对象就会被释放这多妙啊

这样做是不恰当的除非有单一实例的需求不然不要使用单例模式在这里Connection 对象可以同时有几个实例共存不需要是单一实例

单例模式有很多的错误使用案例都与此例子相似它们都是试图使用单例模式管理共享资源的生命周期这是不恰当的

单例类的状态

有状态的单例类

一个单例类可以是有状态的(stateful)一个有状态的单例对象一般也是可变(mutable) 单例对象

有状态的可变的单例对象常常当做状态库(repositary)使用比如一个单例对象可以持有一个int 类型的属性用来给一个系统提供一个数值惟一的序列号码作为某个贩卖系统的账单号码当然一个单例类可以持有一个聚集从而允许存储多个状态

没有状态的单例类

另一方面单例类也可以是没有状态的(stateless) 仅用做提供工具性函数的对象既然是为了提供工具性函数也就没有必要创建多个实例因此使用单例模式很合适一个没有状态的单例类也就是不变(Immutable) 单例类 关于不变模式读者可以参见本书的不变(Immutable )模式一章

多个JVM 系统的分散式系统

EJB 容器有能力将一个EJB 的实例跨过几个JVM 调用由于单例对象不是EJB因此单例类局限于某一个JVM 中换言之如果EJB 在跨过JVM 后仍然需要引用同一个单例类的话这个单例类就会在数个JVM 中被实例化造成多个单例对象的实例出现一个JEE应用系统可能分布在数个JVM 中这时候不一定需要EJB 就能造成多个单例类的实例出现在不同JVM 中的情况

如果这个单例类是没有状态的那么就没有问题因为没有状态的对象是没有区别的但是如果这个单例类是有状态的 那么问题就来了举例来说如果一个单例对象可以持有一个int 类型的属性用来给一个系统提供一个数值惟一的序列号码作为某个贩卖系统的账单号码的话用户会看到同一个号码出现好几次

在任何使用了EJBRMI 和JINI 技术的分散式系统中应当避免使用有状态的单例模式

多个类加载器

同一个JVM 中会有多个类加载器当两个类加载器同时加载同一个类时会出现两个实例在很多JEE 服务器允许同一个服务器内有几个Servlet 引擎时每一个引擎都有独立的类加载器经有不同的类加载器加载的对象之间是绝缘的

比如一个JEE 系统所在的JEE 服务器中有两个Servlet 引擎一个作为内网给公司的网站管理人员使用另一个给公司的外部客户使用两者共享同一个数据库两个系统都需要调用同一个单例类如果这个单例类是有状态的单例类的话那么内网和外网用户看到的单例对象的状态就会不同除非系统有协调机制不然在这种情况下应当尽量避免使用有状态的单例类

上一篇:在Java程序中采用线程获取优异性能

下一篇:Java 6中的线程优化真的有效么?