系统架构技能之设计模式-单件模式

一、开篇

       其实我本来不是打算把系统架构中的一些设计模式单独抽出来讲解的,因为很多的好朋友也比较关注这方面的内容,所以我想通过我理解及平时项目中应用到的一

些常见的设计模式,拿出来给大家做个简单讲解,我这里只是抛砖引玉,如果某个地方讲解的不正确或者不详细,请大家批评指出。园子里面的很多的大牛写的设计模式

都非常的经典,我这里写可能有点班门弄斧的感觉,不过我还是决定把它写出来,希望能对初学者有一定的帮助和指导的作用。当然我这里如果说某个地方解释的有问

题或者说是某个地方写的不符合逻辑之处,还请大家多多指出,提出宝贵意见。

       软件工程中其实有很多总结性的话语,比如说软件=算法+数据结构等等这样的描述,当然我们这里可能算法就是泛指一些软件中的编程方法了,设计模式怎么去

理解呢?为什么要有设计模式?它能带来什么?等等这些都是我们需要讨论的问题。首先我们需要知道设计模式能带来什么。可能这才是我们学习它的主要原因,如果

说不能为我们在书写软件的过程中带来更方面的好处,那我们也不会使用和学习它。

       设计模式是什么?

       设计模式可以简单的理解为解决某一系列问题的完美的解决方案。我们在软件开发的过程中经常遇到设计功能实现的问题,而设计模式正是为了解决软件设计功能

实现时遇到的某一类问题的解决方案。因为一般情况下来说,我们在某个软件功能的开发过程中遇到的功能设计问题,可能是前人很早就遇到过的问题,所以通过这种

设计模式的方式来解决,能让我们在软件实现的过程中少走弯路,或者说是给我们的软件设计带来很好的灵活性和适应性。

       设计模式带来了什么?

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

说明:

       image 当然我这里可能总结还不完全,还请大家补充,我会更新这里面的内容。当然设

计模式带来了这么多的好处,所以我们学习设计模式就显得比较必要了,也是从事软件开发及设计必须掌握的基本技能之一。

       设计模式的简单分类:

       image 当然这里可以简单的分为这3大类,下面我们在讲述的过程中将会分别讲解,当然我这里是以创建型模

式开始讲解,我想创建型模式也是大家项目中必备的吧?下面我就从创建型模式先来讲解。

二、摘要

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

单例模式,后面讲述的设计模式也将使用这样的方式。

       1、什么是单例模式?

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

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

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

三、本文大纲

       a、开篇。

       b、摘要。

       c、本文大纲。

       d、单例模式的简介。

       e、相关应用场景分析。

       f、本文总结。

       g、系列进度。

       h、下篇预告。

四、单例模式的简介

       本章我们将来讲述下单例模式的使用,首先我们来看看单例模式的定义:

       单例模式:是一种软件设计中常用的设计模式,主要是用来控制某个类必须在某个应用程序中只能有一个实例存在。

       有时候我们需要确保整个系统中只有某个类的一个实例存在,这样有利于我们协调控制系统的行为。例如:我们在某个系统中使用了发送短信的这样的服务,那么

我们可能希望通过单一的短信服务类的实例,而不是多个对象实例完成短信的发送服务。这时我们可以通过单例模式来完成。

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

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

        image

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

        1、外部控制的方式

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public  class  Instance
{
     private  List<SendMessage> lists = new  List<SendMessage>();
     private  SendMessage sendInstance;
 
     public  SendMessage SInstance
     {
         get
         {
             return  sendInstance;
         }
     }
 
     public  void  InstanceMethod()
     {
         if  (lists.Count == 0)
         {
             sendInstance = new  SendMessage();
             lists.Add(sendInstance);
         }
         else
         {
             sendInstance = lists[0];
         }
     }
}

       2、内部控制方式

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public  class  Instance1
  {
     private  static  SendMessage sendInstance;
     private  static  object  _lock = new  object ();
 
     protected  Instance1()
     {
     }
 
     public  static  SendMessage SInstance
     {
         get
         {
             lock  (_lock)
             {
                 if  (sendInstance == null )
                     sendInstance = new  SendMessage();
                 return  sendInstance;
             }
         }
     }
}

        这里有几点需要注意的地方,对于第二种方式有几个地方需要说明下,首先是要控制全局只有一个实例的类,请定义成静态实例,这样可以确保只有一个实例对

象,其次,这个对象的构造函数请声明成保护类型的成员,这样可以屏蔽通过直接实例化的形式来访问。通过这样的形式,客户可以不需要知道某个单例实例对象的内

部实现细节。一般情况下满足上面的2点需求就可以完成全局唯一访问入口的控制。当然可能在多线程的情况下采用这样的形式还会有一定的弊端,当然我们这里也简单

的讲解下相应的控制方案。方案如下:

 

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

    

 

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

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

来完成访问。

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

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

五、相关应用场景讲解

        1、场景短信及邮件发送服务

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public  class  CoolInstance
{
     private  CoolInstance()
     {
     }
 
     public  static  readonly  CoolInstance Instance = new  CoolInstance();
 
     /// <summary>
     /// 发送手机短信
     /// </summary>
     public  bool  SendMessage( string  telNumber, string  content)
     {
         return  true ;
     }
 
     /// <summary>
     /// 发送邮件
     /// </summary>
     /// <param name="content"></param>
     /// <param name="toMail"></param>
     public  bool  SendMail( string  content, string  toMail)
     {
         return  true ;
     }
}

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

 

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

       

 

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

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public  class  PrintHelper
  {
      #region 构造函数
      private  PrintHelper()
      {
      }
 
      public  static  readonly  PrintHelper Instance = new  PrintHelper();
      #endregion
 
      #region 打印服务
 
      /// <summary>
      /// 直接打印服务
      /// </summary>
      /// <returns></returns>
      public  bool  Print()
      {
          return  true ;
      }
 
      /// <summary>
      /// 打印预览
      /// </summary>
      /// <returns></returns>
      public  bool  PrintPreview()
      {
          return  true ;
      }
 
      #endregion
  }

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

制单例实例对象的更新呢,有时候可能我们有这样的需求。下面我们来看看如何实现这样的需求。

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

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

 

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

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

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

形式显然就没有办法实现。

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

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

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

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

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

成本和代价也可以接收。

 

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

 

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

 

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

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

        image

六、本文总结

        本文主要讲述了创建型模式中的单例模式,单例模式主要是用来控制系统中的某个类的实例的数量及全局的访问入口点。我们主要讲述了实现单例模式的方式,

分为外部方式及内部方式,当然我们现在采用的方式都是内部方式,还讲述了线程安全的单例模式及带有参数的构造函数的情况,根据配置文件来实现参数值的动态配

置的情况。希望本文的讲解能对不熟悉设计模式的同仁能够了解知道单例模式的应用,而对已熟知单例模式的同仁可以温故而知新,我会努力写好这个系列,当然我这

里可能在大牛的面前可能是班门弄斧吧,不过我会继续努力,争取写出让大家一看就明白的设计模式系列。本文错误之处再所难免,还请大家批评之处,我会继续改

进。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值