下面的代码模拟访问,每单击一次按钮,计数器加1:
Private Sub Buttonl()Sub Buttonl-Click(ByVal semder As_
System.Object,ByVal e As System.EventArgs)Handles Buttonl.Click
Me.Labell.Text = Counter.GetInstance.Count
End Sub
这个计数器是全局的,在Counter中保存状态。
全局变量与单件
在上例中,我们能否用一个窗体的全局变量来代替单件模式?我们定义一个静态的全局变量,在应用启动时初使化这个变量,然后可以在程序的任何地方使用这个变量。在这个例子中,是创建和打开一个窗体。如果我们关闭了这个窗体,会发现将无法再次打开,因为窗体的实例已经被销毁。惟一的办法是创建一个新窗体,因为无法知道哪些模块会调用这个窗体,因此在所有可能的地方都要判断这个窗体是否已经被销毁?是否需要重新创建?系统的维护量可想而知。
可以看出,单件模式维护自身的实例化,在使用时是安全的。一个全局对象无法自行维护,也就无法避免重复创建多个实例,系统资源会被大量占用。更糟糕的是在很多情况下会出现逻辑问题,当这些对象访问相同的资源(例如串口时)时,会发生访问冲突。
单件与实用类中的静态方法
实用类提供系统公用的静态方法,并且也经常采用私有化的构造函数。与单件不同,它没有实例,其中的方法全部是静态方法。
实用类与单件的区别如下。
(1)实用类不保存状态,仅提供功能。
(2)实用类不具有多态性,而单件可以有子类。
(3)单件是对象,实用类只是方法的集合。
应该说在实际应用中,实用类的使用更广泛,而在涉及对象的情况下需要使用单件。例如能否用实用类代替抽象工厂?如果用传统的实现方式,显然不可。因为实用类没有多态性,会导致每个具体工厂的接口不同,在这种情况下必须将工厂对象作为单件。
如果采用反射工厂,那么完全可以不采用单件模式,而将反射工厂作为实用类。因为只需要知道实例化的子类名称就可以完成实例化工作,具体工厂和抽象工厂已经合为一体,多态已无必要。
因此何时使用单件,何时使用实用类要具体情况具体分析,不能一概而论。当然,如果把实用类作为单处理,在实现上是可以的,但没有必要这样做。