热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

通俗道破单例模式

很多时候我们不知不觉中使用着设计模式,自己很多却不知道自己使用了,例如我们在涉及抽象类,接口的时候经常用到装饰者模式,在Wi

    很多时候我们不知不觉中使用着设计模式,自己很多却不知道自己使用了,例如我们在涉及抽象类,接口的时候经常用到装饰者模式,在Winfrom的窗体(当然还是类)复用中经常用到模板方法模式......反正什么是设计模式,学好多态是很重要的,言归正传。

    通常一个类通常可以创建无限个对象,但是有时候需要只有一个对象的类,比如全局资源管理器、缓存管理器等,这种情况下如果有多个对象就会乱掉了。缓存管理器只能有一个,否则把数据扔给一个管理器,却管另外一个要。

    就好比有一个老婆类,他的一个对象对我很好,但是不是随便那个老婆等可以对我好,应该只有我老婆对我好,因此我们要确定这个唯一的老婆。

    单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

现在我们来看一个不是单例模式却有点类似的味道的小代码(至于为什么我稍后解释):

(读取文件内容:)未优化前的代码:

1 static void Main(string[] args)
2 {
3 Stopwatch sw=new Stopwatch();
4 sw.Start();
5 for (int i &#61; 0; i <100000; i&#43;&#43;)
6 {
7 string s&#61;File.ReadAllText(&#64;"d:\1.txt");
8 Console.WriteLine(s);
9 }
10 sw.Stop();
11 Console.WriteLine("耗时&#xff1a;"&#43;sw.Elapsed);
12 Console.ReadKey();
13 }

优化以后&#xff1a;

1 static void Main(string[] args)
2 {
3 Stopwatch sw&#61;new Stopwatch();
4 sw.Start();
5 string s &#61; null;
6 for (int i &#61; 0; i <100000; i&#43;&#43;)
7 {
8 if(s&#61;&#61;null)
9 {
10 s &#61; File.ReadAllText(&#64;"d:\1.txt");
11 }
12 Console.WriteLine(s);
13 }
14 sw.Stop();
15 Console.WriteLine("耗时&#xff1a;"&#43;sw.Elapsed);
16 Console.ReadKey();
17 }

    我先解释为什么不是单例模式&#xff0c;我们应该知道string 是CLR中String类的别名&#xff0c;也就是说我可以在这个小程序中创建很多的String类的对象&#xff0c;而且可以是不同的&#xff08;string a&#61;"";string b&#61;"123"......&#xff09;&#xff0c;所以没有实现确保某一个类只有一个实例的要求。

    我们来看一下优化前后代码执行的不同点&#xff0c;是第二段代码在每次循环的时候先查看下s是不是为空&#xff0c;如果不为空直接打印出s&#xff0c;不需要再次读文件&#xff08;当然此处的判断也是耗时间的哦&#xff0c;好像昨天一个网友还刚发表了什么关于不能从时间的长度看效率&#xff0c;反正我没看&#xff0c;不过这里咱们知道有优化效果就行了&#xff0c;要是真想提高效率必须研究数据结构和算法&#xff09;此处的s起了一个缓存的作用&#xff0c;使执行时间大大缩短。

单例模式的应用&#xff1a;

    有时候我们会遇到这种需求&#xff0c;就是频繁的从服务器下载资料进行对比&#xff0c;或者频繁的操作文件&#xff0c;我想了下vss的工作机制应该也是这个道理&#xff0c;如果我们的开发团队没有修改代码&#xff0c;调用的时候还是会返回缓存中的代码给某个程序员。

    譬如每台计算机可以有若干个打印机&#xff0c;但只能有一个Printer Spooler&#xff0c; 以避免两个打印作业同时输出到打印机中。每台计算机可以有若干传真卡&#xff0c;但是只应该有一个软件负责管理传真卡&#xff0c;以避免出现两份传真作业同时传到传真卡中的情况。每台计算机可以有若干通信端口&#xff0c;系统应当集中管理这些通信端口&#xff0c;以避免一个通信端口同时被两个请求同时调用。

    等等情况... ...

怎么实现单例模式

  实现单例模式的方法很多&#xff0c;常用的就像百度百科里面提到的&#xff1a;

第一种形式: 也是常用的形式。

1 public class Singleton
2 {
3 private static Singleton instance &#61; null;
4 private Singleton()
5 {   //do something  
6 }
7 public static Singleton getInstance()
8 {
9 if (instance &#61;&#61; null)
10 { instance &#61; new Singleton(); }
11 return instance;
12 }
13 } //这个方法比下面的有所改进&#xff0c;不用每次都进行生成对象&#xff0c;只是第一次使用时生成实例&#xff0c;提高了效率  

但是上面这个百度百科没有说明&#xff0c;就是如果是多线程并行操作可能会引起实例的冲突。

所以最好这样啦&#xff1a;

public static Singleton getInstance()
   {
                    return instance;
    }

 第二种形式:

1 public class Singleton
2 {   //在自己内部定义自己的一个实例&#xff0c;只供内部调用  
3 private static Singleton instance &#61; new Singleton();
4 private Singleton()
5 {
6 //do something  
7 }
8 //这里提供了一个供外部访问本class的静态方法&#xff0c;可以直接访问   
9 public static Singleton getInstance()
10 {
11 return instance;
12 }
13 }

 

现在我们模拟频繁读取同一个文件的内容&#xff08;使用单例模式&#xff09;&#xff1a;

1 using System;
2 using System.IO;
3 using System.Diagnostics;
4 using System.Collections.Generic;
5
6 namespace 单例模式
7 {
8 class Program
9 {
10 static void Main(string[] args)
11 {
12 Stopwatch sw &#61; new Stopwatch();
13 sw.Start();
14 for (int i &#61; 0; i <10000; i&#43;&#43;)
15 {
16 //因为Instance是唯一的实例
17 string s&#61; FileCache.instance.ReadFile(&#64;"d:\1.txt");
18 Console.WriteLine(s);
19 }
20 sw.Stop();
21 Console.WriteLine(sw.Elapsed);
22 Console.ReadKey();
23 }
24 }
25 class FileCache
26 {
27 public static readonly FileCache instance &#61; new FileCache();
28 private FileCache()
29 {
30 }
31 //创建一个字典用来保存文件信息&#xff0c;key是文件名&#xff0c;value是文件内容
32 private Dictionary<string, string> dic &#61; new Dictionary<string, string>();
33 public string ReadFile(string path)
34 {
35 if (dic.ContainsKey(path))
36 {
37 return dic[path];
38 }
39 string content &#61; File.ReadAllText(path);
40 dic.Add(path, content);
41 return content;
42 }
43 }
44 }

上面的代码我的硬件配置是i52430,2G CUP 运行了不到一秒。这段代码确保了我们每次操作的都是同一个实例。但是还有个问题就是我们我们及时在程序执行期间修改了文本文件里的内容&#xff0c;显示的仍然没有更新&#xff0c;怎么动态的修改文件并更新显示呢&#xff0c;这里我们就要新建一个内容管理类&#xff0c;保存上次更新的时间和现在内容&#xff0c;就可以了

1 using System;
2 using System.IO;
3 using System.Diagnostics;
4 using System.Collections.Generic;
5 using System.Threading;
6
7 namespace 单例模式
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 Stopwatch sw &#61; new Stopwatch();
14 sw.Start();
15 for (int i &#61; 0; i <100000000; i&#43;&#43;)
16 {
17 //因为Instance是唯一的实例
18 string s&#61; FileCache.instance.ReadFile(&#64;"d:\1.txt");
19 Thread.Sleep(500);
20 Console.WriteLine(s);
21 }
22 sw.Stop();
23 Console.WriteLine(sw.Elapsed);
24 Console.ReadKey();
25 }
26 }
27 class FileCache
28 {
29 public static readonly FileCache instance &#61; new FileCache();
30 private FileCache()
31 {
32 }
33 private Dictionary<string, FileContentManager> dic &#61; new Dictionary<string, FileContentManager>();
34 public string ReadFile(string path)
35 {
36 if (dic.ContainsKey(path))
37 {
38 DateTime lastwritetime &#61; File.GetLastWriteTime(path);//获取上次写入文件的时间
39 if (lastwritetime &#61;&#61; dic[path].LastWriteTime)
40 {
41 return dic[path].Content;
42 }
43 }
44 string content &#61; File.ReadAllText(path);
45 FileContentManager txtmanger &#61; new FileContentManager();
46 ///&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;将信息保存到文件管理类中&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
47 txtmanger.Content &#61; content;
48 txtmanger.LastWriteTime &#61; File.GetLastWriteTime(path);
49 ///&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;将信息保存到文件管理类中&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
50 return content;
51 }
52 }
53 class FileContentManager
54 {
55 public string Content { get;set;}//内容
56 public DateTime LastWriteTime { get; set; }//修改时间
57 }
58 }

运行效果如下&#xff1a;

转:https://www.cnblogs.com/rohelm/archive/2012/04/29/2476107.html



推荐阅读
  • 本文探讨了使用C#在SQL Server和Access数据库中批量插入多条数据的性能差异。通过具体代码示例,详细分析了两种数据库的执行效率,并提供了优化建议。 ... [详细]
  • 本文介绍了一种从与src同级的config目录中读取属性文件内容的方法。通过使用Java的Properties类和InputStream,可以轻松加载并获取指定键对应的值。 ... [详细]
  • 本文介绍了多个关于JavaScript的书籍资源、实用工具和编程实例,涵盖从入门到进阶的各个阶段,帮助读者全面提升JavaScript编程能力。 ... [详细]
  • 20100423:Fixes:更新批处理,以兼容WIN7。第一次系统地玩QT,于是诞生了此预备式:【QT版本4.6.0&#x ... [详细]
  • 本文深入探讨了HTTP请求和响应对象的使用,详细介绍了如何通过响应对象向客户端发送数据、处理中文乱码问题以及常见的HTTP状态码。此外,还涵盖了文件下载、请求重定向、请求转发等高级功能。 ... [详细]
  • PHP 过滤器详解
    本文深入探讨了 PHP 中的过滤器机制,包括常见的 $_SERVER 变量、filter_has_var() 函数、filter_id() 函数、filter_input() 函数及其数组形式、filter_list() 函数以及 filter_var() 和其数组形式。同时,详细介绍了各种过滤器的用途和用法。 ... [详细]
  • 本文详细探讨了HTML表单中GET和POST请求的区别,包括它们的工作原理、数据传输方式、安全性及适用场景。同时,通过实例展示了如何在Servlet中处理这两种请求。 ... [详细]
  • Ihaveastringwithquotesaroundthepathasfollows:我在路径周围有一个带引号的字符串,如下所示:C:\ProgramFiles(x ... [详细]
  • MySQL DateTime 类型数据处理及.0 尾数去除方法
    本文介绍如何在 MySQL 中处理 DateTime 类型的数据,并解决获取数据时出现的.0尾数问题。同时,探讨了不同场景下的解决方案,确保数据格式的一致性和准确性。 ... [详细]
  • Unity编辑器插件:NGUI资源引用检测工具
    本文介绍了一款基于NGUI的资源引用检测工具,该工具能够帮助开发者快速查找和管理项目中的资源引用。其功能涵盖Atlas/Sprite、字库、UITexture及组件的引用检测,并提供了替换和修复功能。文末提供源码下载链接。 ... [详细]
  • 本文介绍如何在PostgreSQL数据库中正确插入和处理JSON数据类型,确保数据完整性和避免常见错误。 ... [详细]
  • C# LiNQ 查询 join连接
    C# LiNQ 查询 join连接 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 在Java中,this是一个引用当前对象的关键字。如何通过this获取并显示其所指向的对象的属性和方法?本文详细解释了this的用法及其背后的原理。 ... [详细]
  • 在软件开发过程中,MD5加密是一种常见的数据保护手段。本文将详细介绍如何在C#中使用两种不同的方式来实现MD5加密:字符串加密和流加密。 ... [详细]
author-avatar
七仙女跳皮筋
这个家伙很笨,什么也不会!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有