博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式 单件模式(Signleton Pattern)
阅读量:4332 次
发布时间:2019-06-06

本文共 3806 字,大约阅读时间需要 12 分钟。

    尽管在某种程度上,单件模式是限制而不是改进类的创建,但它仍和其他创建模式分在一组。单件模式可以保证一类有且只有一个实例,并提供一个访问它的全局访问点,在程序设计过程中,有很多情况需要确保一个类只能有一个实例。例如系统中能有一个窗口管理器,一个数据库引擎的访问点。PC机中可能有几个串口,但只能有一个COM1实例。

使用静态方法创建单件
    让一个类只有一个实例,最容易的方法就是在类中嵌入一个静态变量,并在第一个类实例中设置改变量,而且每次进入构造函数都要检查。不管类有多少实例,静态变量只能有一个实例。为了防止类被多次实例化,我们把构造函数声明为私有的,这样只能在类的静态方法里创建一个实例。下面创建一个
getSpooler方法,返回Spooler的一个实例,如果类已经被实例化,返回值为null。

1 using System;  2  3 namespace GlobalSpooler  4 {
5 /// 6 /// Summary description for Spooler. 7 /// 8 public class Spooler {
9 private static bool instance_flag= false; 10 private Spooler() {
11 } 12 public static Spooler getSpooler() {
13 if (! instance_flag) 14 return new Spooler (); 15 else 16 return null; 17 } 18 19 } 20 }

  这中方法的主要优点是,如果单件存在了,不需要考虑异常处理,因为只不过getSpooler方法返回一个空值而已。

1 Spooler sp1 = Spooler.getSpooler(); 2 if (sp1 != null) 3 Console.WriteLine ("Got 1 spooler"); 4 Spooler sp2 = Spooler.getSpooler (); 5 if (sp2 == null) 6 Console.WriteLine ("Can\'t get spooler");

如果视图直接创建Spoolet类的实例,编译会失败,因为构造函数被声明为私有的。

1 //fails at compile time 2 Spooler sp3 = new Spooler ();

最后,如果需要修改程序,允许该类有两个或者三个实例,则修改spooler类可以很容易实现这一点。

    
异常与实例
    前面方法有个缺点,需要程序员检查方法的返回值,以确保它不为空。让程序员始终记得去检查错误的设想是导致失败的开始,应该尽量避免。我们换种方法,创建一个这样的类,如果视图多次实例化该类,它会抛出一个异常,这时才需要程序员采取行动,因而这时一个安全的方法,这里先为这个例子创建异常类。

1 using System;  2  3 namespace singleSpooler  4 {
5 /// 6 /// Summary description for SingletonException. 7 /// 8 public class SingletonException:Exception {
9 //new exception type for singleton classes 10 public SingletonException(string s):base(s) { 11 } 12 } 13 }

抛出异常

接下来给出PrintSpooler类的框架。这里略去打印方法,只集中在单件模式

1 using System;  2  3 namespace singleSpooler  4 {
5 /// 6 /// Prototype of Spooler Singleton 7 /// such that only one instane can ever exist. 8 /// 9 public class Spooler {
10 static bool instance_flag = false; //true if one instance 11 public Spooler() {
12 if (instance_flag) 13 throw new SingletonException("Only one printer allowed"); 14 else 15 instance_flag=true; //set flag for one instance 16 Console.WriteLine ("printer opened"); 17 } 18 } 19 }

创建一个实例

我们已经在PrintSpooler类里创建了一个简单的单件模式,接下来就去了解如果使用它

1 using System;  2  3 namespace singleSpooler  4 {
5 /// 6 /// Summary description for Class1. 7 /// 8 public class singleSpooler {
9 static void Main(string[] args) { 10 Spooler pr1, pr2; 11 //open one printer--this should always work 12 Console.WriteLine ("Opening one spooler"); 13 try {
14 pr1 = new Spooler(); 15 } 16 catch (SingletonException e) {
17 Console.WriteLine (e.Message); 18 } 19 //try to open another printer --should fail 20 Console.WriteLine ("Opening two spoolers"); 21 try{
22 pr2 = new Spooler(); 23 } 24 catch (SingletonException e) {
25 Console.WriteLine (e.Message); 26 } 27 } 28 } 29 }

执行结果

提供一个单件的全局访问点

    由于使用电击模式提供一个类的全局访问点,即使C#中没有全局变量,设计程序是也必须为整个程序提供引用单件方法。一种解决方案是在程序的开头创建单件模式,并将其作为参数传递到使用它的类中。这种方法的 缺点是,在某次程序运行中,可能不需要所有的单件,这样会影响程序的性能。

1 prl = iSpooler.Instance(); 2 Customers cust = new Customers(prl);

    另一种更灵活的解决方案是,在程序中创建一个所有单件类的注册表,并使用注册表始终是可用的,每一次实例化一个组件,都将其记录在注册表中。程序的任何部分都是用标示符串访问任何一个单件实例,并能取回相应的实例变量。注册表的缺点是减少了类型检查,因为注册表中的单件可能把所有的单件都保存成对象型,例如,Hashtable中的对象类型,另外,注册表本身可能也是一个单件,必须使用构造函数或者其他set函数吧它传递给程序的所有部分。提供一个全局访问点的最常用的方式就是使用类的静态方法。类名始终是可用的,静态方法只能由类调用不能由类的实例调用,所以不管程序中有多少方法调用该方法,永远只能有一个这样的实例。

单例模式的其他效果
1.子类化一个单件很难,因为只有在基类单件没有实例化时,才能实现这一点。
2.可能很容易修改一个单件,使它有少数几个实例,这样做事允许的而且有意义的。
   

转载于:https://www.cnblogs.com/sunjinpeng/archive/2012/03/27/2419729.html

你可能感兴趣的文章
两台电脑如何实现共享文件
查看>>
组合模式Composite
查看>>
程序员最想得到的十大证件,你最想得到哪个?
查看>>
我的第一篇CBBLOGS博客
查看>>
【MyBean调试笔记】接口的使用和清理
查看>>
07 js自定义函数
查看>>
jQueru中数据交换格式XML和JSON对比
查看>>
form表单序列化后的数据转json对象
查看>>
[PYTHON]一个简单的单元測试框架
查看>>
iOS开发网络篇—XML数据的解析
查看>>
[BZOJ4303]数列
查看>>
一般处理程序在VS2012中打开问题
查看>>
C语言中的++和--
查看>>
thinkphp3.2.3入口文件详解
查看>>
POJ 1141 Brackets Sequence
查看>>
Ubuntu 18.04 root 使用ssh密钥远程登陆
查看>>
Servlet和JSP的异同。
查看>>
虚拟机centOs Linux与Windows之间的文件传输
查看>>
ethereum(以太坊)(二)--合约中属性和行为的访问权限
查看>>
IOS内存管理
查看>>