热门标签 | 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



推荐阅读
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文介绍了在CentOS 6.4系统中更新源地址的方法,包括备份现有源文件、下载163源、修改文件名、更新列表和系统,并提供了相应的命令。 ... [详细]
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社区 版权所有