设计模式学习(一)—— 单件模式
在程序中,有很多类是需要确保有且仅有一个实例的,这样才能保证它的正确性和高效性。例如一个系统只能有一个窗口管理器或者是打印的后台处理程序。
使用静态方法来创建单件
使得一个类只有一个实例的最容易方法就是在类中包含一个静态变量,在变量在第一个实例生成时被初始化,然后每次进入构造函数时就做检查,如果此变量还不存在,那么就返回一个新的实例;否则,就返回一个新的实例。
public class Spooler
{
private static bool instance_flag = false;
private Spooler(){}
public static Spooler getSpoller()
{
if(! instance_flag)
{
return new Spooler();
}
else
{
return null;
}
}
}
在上面的代码中我们将构造函数声明为私有的,这样我们就可以防止类的使用者任意的创建新的实例,而是只能通过静态成员函数的方法来创建。在静态方法中,如果类已经被实例过了,就返回null。
下面是使用这个类的一段代码。
Spooler sp = Spooler.getSpoller();
if(sp != null)
{
Console.WriteLine("Get one Spooler!\n");
}
Spooler sp2 = Spooler.getSpoller();
if(sp2 == null)
{
Console.WriteLine("Instance already exists!\n");
}
如果尝试直接创建Splooer的实例,那么在编译时就会失败,因为构造函数已经被声明为私有的了。
//编译时失败
Splooer sp = new Splooer();
异常和实例
上述方法有一个缺点,就是总是需要编程者检查getSplooer()方法的返回值,但是往往编程者会忘记进行这项检查。
所以我们将对上述类进行一个改进:使用异常,如果打算对它实例化超过一次,该类就会抛出一个异常。
public class SingletonException:Exception
{
public SingletonException(string s):base(s)
{
}
}
public class Spooler
{
private static bool instance_flag = false;
public Spooler()
{
if(instance_flag)
{
throw new SingletonException("Only one instance allowed!\n");
}
else
{
instance_flag = true;
Console.WriteLine("printer opened!\n");
}
}
public static void Main()
{
Spooler sp1,sp2 ;
Console.WriteLine("opening the first printer!\n");
try
{
sp1 = new Spooler();
}
catch(SingletonException e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("opening the second printer!\n");
try
{
sp2 = new Spooler();
}
catch(SingletonException e)
{
Console.WriteLine(e.Message);
}
}
}
单件模式的特点
- 从单件类继承会比较困难,因为只有在单件基类还没有被实例化的情况下这一做法才是有效的。
- 可以很容易的修改单件类来支持创建不止一个实例。