求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
 
系统架构技能之设计模式-单件模式

2010-10-27 作者:CallHot 来源:CallHot 的blog

 

一、开篇

其实我本来不是打算把系统架构中的一些设计模式单独抽出来讲解的,因为很多的好朋友也比较关注这方面的内容,所以我想通过我理解及平时项目中应用到的一些常见的设计模式,拿出来给大家做个简单讲解,我这里只是抛砖引玉,如果某个地方讲解的不正确或者不详细,请大家批评指出。园子里面的很多的大牛写的设计模式都非常的经典,我这里写可能有点班门弄斧的感觉,不过我还是决定把它写出来,希望能对初学者有一定的帮助和指导的作用。当然我这里如果说某个地方解释的有问题或者说是某个地方写的不符合逻辑之处,还请大家多多指出,提出宝贵意见。

软件工程中其实有很多总结性的话语,比如说软件=算法+数据结构等等这样的描述,当然我们这里可能算法就是泛指一些软件中的编程方法了,设计模式怎么去理解呢?为什么要有设计模式?它能带来什么?等等这些都是我们需要讨论的问题。首先我们需要知道设计模式能带来什么。可能这才是我们学习它的主要原因,如果说不能为我们在书写软件的过程中带来更方面的好处,那我们也不会使用和学习它。

设计模式是什么?

设计模式可以简单的理解为解决某一系列问题的完美的解决方案。我们在软件开发的过程中经常遇到设计功能实现的问题,而设计模式正是为了解决软件设计功能实现时遇到的某一类问题的解决方案。因为一般情况下来说,我们在某个软件功能的开发过程中遇到的功能设计问题,可能是前人很早就遇到过的问题,所以通过这种设计模式的方式来解决,能让我们在软件实现的过程中少走弯路,或者说是给我们的软件设计带来很好的灵活性和适应性。

设计模式带来了什么?

 设计模式是源于实践,并且每种设计模式都包含了一个问题描述,问题涉及到的参与者并且提供了一个实际的解决方案。设计模式的好处我们可以通过下图来简单说明:

当然我这里可能总结还不完全,还请大家补充,我会更新这里面的内容。当然设计模式带来了这么多的好处,所以我们学习设计模式就显得比较必要了,也是从事软件开发及设计必须掌握的基本技能之一。

设计模式的简单分类:

当然这里可以简单的分为这3大类,下面我们在讲述的过程中将会分别讲解,当然我这里是以创建型模式开始讲解,我想创建型模式也是大家项目中必备的吧?下面我就从创建型模式先来讲解。

二、摘要

本文将主要讲解创建型模式中的单例模式先来讲解,因为单例模式是最简单也是最容易理解的设计模式,上手快,易使用的设计模式。本文将从下面的流程来讲解单例模式,后面讲述的设计模式也将使用这样的方式。

1、什么是单例模式?

2、单例模式的应用场景。

3、举例说明单例模式的使用。

4、总结单例模式的用法。

三、本文大纲

a、开篇。

b、摘要。

c、本文大纲。

d、单例模式的简介。

e、相关应用场景分析。

f、本文总结。

g、系列进度。

h、下篇预告。

四、单例模式的简介

本章我们将来讲述下单例模式的使用,首先我们来看看单例模式的定义:单例模式:是一种软件设计中常用的设计模式,主要是用来控制某个类必须在某个应用程序中只能有一个实例存在。

有时候我们需要确保整个系统中只有某个类的一个实例存在,这样有利于我们协调控制系统的行为。例如:我们在某个系统中使用了发送短信的这样的服务,那么我们可能希望通过单一的短信服务类的实例,而不是多个对象实例完成短信的发送服务。这时我们可以通过单例模式来完成。

上图简单描述了单例模式应用的位置。

我们看看单例模式的几种实现方式:

下面我们来举例说明下这2种方式的实现。

1、外部控制的方式

01 public class Instance 
02
03      private List<SendMessage> lists = new List<SendMessage>(); 
04      private SendMessage sendInstance; 
05  
06      public SendMessage SInstance 
07     
08          get 
09         
10              return sendInstance; 
11         
12     
13  
14      public void InstanceMethod() 
15     
16          if (lists.Count == 0) 
17         
18              sendInstance = new SendMessage(); 
19              lists.Add(sendInstance); 
20         
21          else 
22         
23              sendInstance = lists[0]; 
24         
25     
26 }

2、内部控制方式

01 public class Instance1 
02  
03      private static SendMessage sendInstance; 
04      private static object _lock = new object (); 
05  
06      protected Instance1() 
07     
08     
09  
10      public static SendMessage SInstance 
11     
12          get 
13         
14              lock (_lock) 
15             
16                  if (sendInstance == null
17                      sendInstance = new SendMessage(); 
18                  return sendInstance; 
19             
20         
21     
22 }

这里有几点需要注意的地方,对于第二种方式有几个地方需要说明下,首先是要控制全局只有一个实例的类,请定义成静态实例,这样可以确保只有一个实例对象,其次,这个对象的构造函数请声明成保护类型的成员,这样可以屏蔽通过直接实例化的形式来访问。通过这样的形式,客户可以不需要知道某个单例实例对象的内部实现细节。一般情况下满足上面的2点需求就可以完成全局唯一访问入口的控制。当然可能在多线程的情况下采用这样的形式还会有一定的弊端,当然我们这里也简单的讲解下相应的控制方案。方案如下:

1 public class CoolInstance 
2
3      private CoolInstance() 
4     
5     
6      public static readonly CoolInstance Instance = new CoolInstance(); 
7 }

看吧很简单吧,当然我们这里来简单解释下原理:

1、我们先把构造函数声明为私有的构造函数,这样我们能够屏蔽外部通过实例化的形式访问内部的成员函数。所有的成员函数的访问必须通过静态成员Instance来完成访问。

2、这段代码通过定义公共、静态、只读的成员相当于在类被第一次使用时执行构造,由于是只读的,所以一旦构造后不允许修改,就不用担心不安全的问题。

相信对上面的介绍大家应该基本上知道单例模式的应用了,那么下面我们来看看项目中的实际应用场景及用法。

五、相关应用场景讲解

1、场景短信及邮件发送服务那么我们将采用上面介绍的最“COOL”的方式来进行控制,提供发送短信及发送邮件的服务。

01 public class CoolInstance 
02
03      private CoolInstance() 
04     
05     
06  
07      public static readonly CoolInstance Instance = new CoolInstance(); 
08  
09      /// <summary> 
10      /// 发送手机短信 
11      /// </summary> 
12      public bool SendMessage( string telNumber, string content) 
13     
14          return true
15     
16  
17      /// <summary> 
18      /// 发送邮件 
19      /// </summary> 
20      /// <param name="content"></param> 
21      /// <param name="toMail"></param> 
22      public bool SendMail( string content, string toMail) 
23     
24          return true
25     
26 }

我们再来看看调用类中如何书写完成调用。例如我们有个订单类,当有人新下订单时,将给卖家发送短信提醒功能。

01 /// <summary> 
02   /// 订单业务 
03 /// </summary> 
04 public class Order 
05
06      public int Save() 
07     
08          //先是将订单的相关信息生成, 
09          this .InitOrderInfo(); 
10  
11          //执行订单的持久化方法 
12          int count= this .Add(); 
13  
14          //发送短信 
15          CoolInstance.Instance.SendMessage( string .Empty, string .Empty); 
16          //发送邮件 
17          CoolInstance.Instance.SendMail( string .Empty, string .Empty); 
18  
19          return count; 
20     
21  
22      /// <summary> 
23      /// 初始化订单信息 
24      /// </summary> 
25      private void InitOrderInfo() 
26     
27     
28  
29      /// <summary> 
30      /// 新增订单信息 
31      /// </summary> 
32      /// <returns></returns> 
33      private int Add() 
34     
35          return 0; 
36     
37 }

这样我们就完成了短信发送服务及邮件发送服务的控制。主要还是根据自己的业务需要。

2、例如我们现在提供一个系统日志服务或者打印或者扫描的服务,我们希望全局只有一个访问入口,那么我们就可以通过这样的单例模式来实现这样的需求。

01 public class PrintHelper 
02  
03       #region 构造函数 
04       private PrintHelper() 
05      
06      
07  
08       public static readonly PrintHelper Instance = new PrintHelper(); 
09       #endregion 
10  
11       #region 打印服务 
12  
13       /// <summary> 
14       /// 直接打印服务 
15       /// </summary> 
16       /// <returns></returns> 
17       public bool Print() 
18      
19           return true
20      
21  
22       /// <summary> 
23       /// 打印预览 
24       /// </summary> 
25       /// <returns></returns> 
26       public bool PrintPreview() 
27      
28           return true
29      
30  
31       #endregion 
32   }

具体的调用类我就不写相应的代码,都和上面的形式类同,下面我们讲解下可能更特殊的需求,有时候我们可能需要更新我们创建的唯一实例,这时我们如何控制单例实例对象的更新呢,有时候可能我们有这样的需求。下面我们来看看如何实现这样的需求。

3、可更新单例对象的场景

首先我们先说下什么情况下会遇到这样的更新方式呢?例如我们想在单例模式的类的构造函数是带有一定参数的情形时:

01 public class UpdateHelper 
02
03      private string type = string .Empty; 
04      private static object _lock = new object (); 
05      private static UpdateHelper instance; 
06      private UpdateHelper( string valueType) 
07     
08          type = valueType; 
09     
10  
11      public static UpdateHelper Instance 
12     
13          get 
14         
15              lock (_lock) 
16             
17                  if (instance == null
18                 
19                      //如果这里有多个条件需求的话,可能写起来会比较复杂,那么有更好的方式来处理吗? 
20                      instance = new UpdateHelper("test!" ); 
21                 
22  
23                  return instance; 
24             
25         
26     
27 }

那么我们来分析几种办法,有没有更好的办法来处理呢?

1、首先我们不能手动实例化,所以我们没有办法动态传入构造函数参数,只能在类的内部指定这个参数,但是有时候我们需要动态的更新这个参数,那么这样的形式显然就没有办法实现。

2、通过属性的方式,来动态的设置属性的内容来完成输出参数的改变,但是这样的方式可能太过自由,无法满足单例模式的初衷。

3、接口方式,因为接口必须要靠类来实现,所以更不靠谱,可以不考虑这样的方式。

4、通过Attribute的方式来将信息动态的注入到构造函数中,但是怎么说这样的方式是不是太兴师动众了呢?毕竟单例模式本来就是很简单的。

5、通过配置文件,通过config文件配置节点的形式来动态的配置相关信息,实现更新实例对象内容的情况。

通过上面的5种情况的分析,那么通过2、4、5可以实现这个要求,但是对比相应的代价来说,5的方式是最灵活也是最符合单例模式本来的规范要求,相对来说成本和代价也可以接收。

1 <? xml version = "1.0" encoding = "utf-8" ?> 
2 < configuration
3    < system.Web
4      < add key = "ssss" >value</ add
5   
6    </ system.Web
7 </ configuration >

那么我们上面的单力模型中的代码只需要稍微的变化下即可,请看如下代码:

01 public class UpdateHelper 
02
03      private string type = string .Empty; 
04      private static object _lock = new object (); 
05      private static UpdateHelper instance; 
06      private UpdateHelper( string valueType) 
07     
08          type = valueType; 
09     
10  
11      public static UpdateHelper Instance 
12     
13          get 
14         
15              lock (_lock) 
16             
17                  if (instance == null
18                 
19                      //如果这里有多个条件需求的话,可能写起来会比较复杂,那么有更好的方式来处理吗? 
20                      instance = new UpdateHelper(System.Configuration.ConfigurationManager.AppSettings["ssss" ].ToString()); 
21                 
22  
23                  return instance; 
24             
25         
26     
27 }

我想到这里大家都对单例模式有个简单的认识了,本文的内容就讲到这里。我们来回顾下我们讲述的内容:

六、本文总结

本文主要讲述了创建型模式中的单例模式,单例模式主要是用来控制系统中的某个类的实例的数量及全局的访问入口点。我们主要讲述了实现单例模式的方式,分为外部方式及内部方式,当然我们现在采用的方式都是内部方式,还讲述了线程安全的单例模式及带有参数的构造函数的情况,根据配置文件来实现参数值的动态配置的情况。希望本文的讲解能对不熟悉设计模式的同仁能够了解知道单例模式的应用,而对已熟知单例模式的同仁可以温故而知新,我会努力写好这个系列,当然我这里可能在大牛的面前可能是班门弄斧吧,不过我会继续努力,争取写出让大家一看就明白的设计模式系列。本文错误之处再所难免,还请大家批评之处,我会继续改进。



如何向妻子解释OOD
OOAD与UML笔记
UML类图与类的关系详解
UML统一建模语言初学
总结一下领域模型的验证
基于 UML 的业务建模


面向对象的分析设计
基于UML的面向对象分析设计
UML + 嵌入式系统分析设计
关系数据库面向OOAD设计
业务建模与业务架构
使用用例进行需求管理


某航空IT部门 业务分析与业务建模
联想 业务需求分析与建模
北京航管科技 EA工具与架构设计
使用EA和UML进行嵌入式系统分析
全球最大的茶业集团 UML系统分析
华为 基于EA的嵌入式系统建模
水资源服务商 基于EA进行UML建模
更多...