在什么环境下利用单例模式
利用单例模式的条件
利用单例模式有一个很重要的须要条件:
在一个系统要求一个类只有一个实例时才该当利用单例模式。反过来说,假如一个类可以有几个实例共存,那么就没有须要利用单例类。可是有履历的读者大概会看到许多不内地利用单例模式的例子,可见做到上面这一点并不容易,下面就是一些这样的环境。
例子一
问:我的一个系统需要一些"全程"变量。进修了单例模式后,我发明可以利用一个单例类盛放所有的"全程"变量。请问这样做对吗?
答:这样做是违背单例模式的用意的。单例模式只该当在有真正的"单一实例"的需求时才可利用。
一个设计恰当的系统不应当有所谓的"全程"变量,这些变量该当放到它们所描写的实体所对应的类中去。将这些变量从它们所描写的实体类中抽出来, 放到一个不相干的单例类中去,会使得这些变量发生错误的依赖干系和耦合干系。
例子二
问:我的一个系统需要打点与数据库的毗连。进修了单例模式后,我发明可以利用一个单例类包装一个Connection 工具,并在finalize()要领中封锁这个Connection 工具。这样的话,在这个单例类的实例没有被人引用时,这个finalize() 工具就会被挪用,因此,Connection 工具就会被释放。这多妙啊。
答:这样做是不得当的。除非有单一实例的需求,否则不要利用单例模式。在这里Connection 工具可以同时有几个实例共存,不需要是单一实例。
单例模式有许多的错误利用案例都与此例子相似,它们都是试图利用单例模式打点共享资源的生命周期,这是不得当的。
单例类的状态
有状态的单例类
一个单例类可以是有状态的(stateful),一个有状态的单例工具一般也是可变(mutable) 单例工具。
有状态的可变的单例工具经常当做状态库(repositary)利用。好比一个单例工具可以持有一个int 范例的属性,用来给一个系统提供一个数值惟一的序列号码,作为某个贩卖系统的账单号码。虽然,一个单例类可以持有一个聚积,从而答允存储多个状态。
没有状态的单例类
另一方面,单例类也可以是没有状态的(stateless), 仅用做提供东西性函数的工具。既然是为了提供东西性函数,也就没有须要建设多个实例,因此利用单例模式很符合。一个没有状态的单例类也就是稳定(Immutable) 单例类; 关于稳定模式,读者可以拜见本书的"稳定(Immutable )模式"一章。
多个JVM 系统的分手式系统
EJB 容器有本领将一个EJB 的实例跨过几个JVM 挪用。由于单例工具不是EJB,因此,单例类范围于某一个JVM 中。换言之,假如EJB 在跨过JVM 后仍然需要引用同一个单例类的话,这个单例类就会在数个JVM 中被实例化,造成多个单例工具的实例呈现。一个J2EE应用系统大概漫衍在数个JVM 中,这时候不必然需要EJB 就能造成多个单例类的实例呈此刻差异JVM 中的环境。
假如这个单例类是没有状态的,那么就没有问题。因为没有状态的工具是没有区此外。可是假如这个单例类是有状态的, 那么问题就来了。举例来说,假如一个单例工具可以持有一个int 范例的属性,用来给一个系统提供一个数值惟一的序列号码,作为某个贩卖系统的账单号码的话,用户会看到同一个号码呈现好屡次。
在任何利用了EJB、RMI 和JINI 技能的分手式系统中,该当制止利用有状态的单例模式。
多个类加载器
同一个JVM 中会有多个类加载器,当两个类加载器同时加载同一个类时,会呈现两个实例。在许多J2EE 处事器答允同一个处事器内有几个Servlet 引擎时,每一个引擎都有独立的类加载器,经有差异的类加载器加载的工具之间是绝缘的。
好比一个J2EE 系统地址的J2EE 处事器中有两个Servlet 引擎:一个作为内网给公司的网站打点人员利用;另一个给公司的外部客户利用。两者共享同一个数据库,两个系统都需要挪用同一个单例类。假如这个单例类是有状态的单例类的话,那么内网和外网用户看到的单例工具的状态就会差异。除非系统有协调机制,否则在这种环境下该当只管制止利用有状态的单例类。