小A:“应该怎么去应用单体模式哩?”
大B:“首先是要建立目录,数据库连接或Socket 连接要受到一定的限制,必须保持同一时间只能有一个连接的存在等这样的单线程操作。使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)。”
小A:“关于数据库连接应用单体模式的问题应该怎么去解决?”
大B:“关于把单例模式应用到数据库connection的问题较为复杂,如果是简单地把一个connection对象封存在单例对象中,那么在J2EE环境中这是错误的。如果数据库连接做成单例模式也就是说系统只会存在一个数据库连接实例,大家公用。实例不可以并发使用。因此存在排队,单例模式管理是需要排队的。资源有两种,一种需要排队,一种不需要排队,或者需要一种复杂的排队,譬如数据库就是复杂的排队问题,系统的排队是不可避免的,应该由数据库引擎自行解决。解决方式就是纪录的locking,而locking不应该由Java程序解决。尽量将排队的工作交给更低一层来做,这样可以获得更高的效率。但是在单用户系统中这并不是什么严重的问题,因为在某一个时刻只有一个用户在使用,唯一的问题就是系统可能需要几个connection,譬如两个、三个等,而不是一个。J2EE服务器系统中单例模式可以用来管理一个数据库连接池(connection pool)。单例模式可以用来保存这样一个connection pool,在初始化的时候创建譬如100个connection对象,然后再需要的时候提供一个,用过之后返回到pool中。如果不是用单例模式的话,这个pool存在哪里,就是一个问题。最后可能只好存到Application对象中。”
小A:“那关于‘全局’变量的问题又应该如何去解决?”
大B:“使用单例模式来存放‘全局’变量是违背单例模式的用意的,单例模式只在有真正的‘单一实例’的需求时才可以使用。其次,一个设计得当的系统不应该有所谓的‘全局’变量的。这些变量应该放到他们所描述的实体所对应的类中去。将这些变量从他们所描述的实体类中抽出来,放到一个不相干的单体类中去,使得这些变量产生错误的依赖关系和耦合关系。所以,如果需要的话,我们可以将一个承担了责任的类作为一个单体类来实现,而不仅仅是为了一个‘全局’变量。”
大B:“有时使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的。总之:Singleton模式看起来简单,使用方法也很方便,但是真正用好,是非常不容易,需要对Java的类和线程内存等概念有相当的了解。如果你的应用基于容器,那么Singleton模式少用或者不用,可以使用相关替代技术。”