Singleton Pattern

单件模式:(Singleton pattern)
1.目的
1) 在全局范围内控制一个对象只能有一个唯一的实例 


2.作用
具体程序设计中往往需要保证一个类只能有一个实例
如:
一个客户端只能有一个数据库连接;
为了节省资源,配置文件只能被加载一次;
虽然又多个串行端口,但使能又一个COM1实例(比如对嵌入式编程,对外设开发驱动程序等等)


3.单件模式的机制
1) 单件模式保证只能常见对象的唯一一个实例
2) 单件模式提供一个全局访问点:(不让外边来创建实例,提供一个方法来获取我的实例,该方法就是全局的访问点)
3) 通过静态变量C#,Java中(static),VB中(Shared)来实现唯一性.(静态成员在全局范围内是唯一的不属于某个对象属于类)


4.多线程下的单件模式 (多线程下存在多线程同步的问题,如果不控制多线程同步,那么多线程同时访问单件模式这个方法,可能会生成不唯一的实例,所以需要控制多线程同步问题)
1) 在多线程下,保证一个类只有唯一一个实例
2) C#->lock,Java->synchronized
开始,结束.public static load()

3)为什么在多线程下可能会生成不唯一的实例呢?
假如有两个线程,同时访问GetInstances()这个方法,第一个线程执行到singleton = new Singleton();这行
第二个线程执行到 { 这行,很明显会产生两个实例了. 

 

 

ClassDiagram:

 

 

 

SequenceDiagram:

 

 

 

单线程下的单例示例:

    class Program 
    { 
        static void Main(string[] args) 
        { 

            Singleton single1 = Singleton.GetInstances(); 

            Singleton single2 = Singleton.GetInstances(); 

            //结果为ture,这样一个简单的单例模式就完成了!!! 
            Console.WriteLine(single1==single2);  
           
            Console.ReadKey(); 
        } 
    } 

    /// 
    /// 单线程下的单例模式 
    /// 
    class Singleton 
    { 
        //用静态变量的目的是为了保证唯一性(静态变量是唯一的,在类中共享的不属于某个对象) 
        public static Singleton singleton = null; 

        private Singleton() 
        { 
           
        } 
         //饿汉式写法.这种写法可能在多个线程访问事出现两个对象(虽然可能行很小!)
        public static Singleton GetInstances() 
        { 
            if (singleton==null) 
            { 
                singleton = new Singleton(); 
            } 
            return singleton; 
        } 

    } 

  

  

   

 class Client
    {
        static void Main(string[] args)
        {
            Singleton s1 = Singleton.GetInstance();
            Singleton s2 = Singleton.GetInstance();

            Console.WriteLine(s1 == s2);

            Console.ReadKey();
        }
    }

    public class Singleton
    {  //静态成员在类初始化时只会被加载一次.
        private static Singleton singleton = new Singleton();

        //懒汉式写法(这种方式多线程下不会出现两个对象.)
        public static Singleton GetInstance()
        {
            return singleton;
        }
    }

 

 

  

   多线程下的示例:

        static void Main(string[] args)
        {

            Singleton single1 = Singleton.GetInstances();

            Singleton single2 = Singleton.GetInstances();
            //结果为ture,这样一个简单的单例模式就完成了!!!
            Console.WriteLine(single1 == single2);

            Console.ReadKey();

        }
    }

    /// <summary>
    /// 单线程下的单例模式
    /// </summary>
    class Singleton
    {
        //用静态变量的目的是为了保证唯一性(静态变量是唯一的,在类中共享的不属于某个对象)
        public static Singleton singleton = null;

        private Singleton()
        {

        }


        public static Singleton GetInstances()
        {
            //lock(同步)的作用:保证在lock代码块中的代码在同一时刻只能有同一个线程可以访问它
            /*这和数据库的锁一个意思,通俗的讲当一个线程执行到lock里的代码块,第二个线程也来了
            来了后被lock挡住,档在外面了,等第一个线程执行完以后,才去执行第二个线程(线程同步的概念) 
            */
            lock (typeof(Singleton))
            {
                if (singleton == null)
                {
                    singleton = new Singleton();
                }
                return singleton;
            }
        }
    }

  

  

using System;
using System.Collections;
using System.Threading;

// "Singleton"
class LoadBalancer
{
  // Fields
  private static LoadBalancer balancer;
  private ArrayList servers = new ArrayList();
  private Random random = new Random();

  // Constructors (protected)
  protected LoadBalancer()
  {
    // List of available servers
    servers.Add( "ServerI" );
    servers.Add( "ServerII" );
    servers.Add( "ServerIII" );
    servers.Add( "ServerIV" );
    servers.Add( "ServerV" );
  }

  // Methods
  public static LoadBalancer GetLoadBalancer()
  {
    // Support multithreaded applications through
    // "Double checked locking" pattern which avoids
    // locking every time the method is invoked
    if( balancer == null )
    {
      // 只允许一个线程访问
      Mutex mutex = new Mutex();
      mutex.WaitOne();

      if( balancer == null )
        balancer = new LoadBalancer();

      mutex.Close();
    }
    return balancer;
  }

  // Properties
  public string Server
  {
    get
    {
      // Simple, but effective random load balancer
      int r = random.Next( servers.Count );
      return servers[ r ].ToString();
    }
  }
}

/** <summary>
/// SingletonApp test
/// </summary>
///
public class SingletonApp
{
  public static void Main( string[] args )
  {
    LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
    LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
    LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
    LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

    // Same instance?
    if( (b1 == b2) && (b2 == b3) && (b3 == b4) )
      Console.WriteLine( "Same instance" );

    // Do the load balancing
    Console.WriteLine( b1.Server );
    Console.WriteLine( b2.Server );
    Console.WriteLine( b3.Server );
    Console.WriteLine( b4.Server );
  }
}

 

  

C#的独特语言特性决定了C#拥有实现Singleton模式的独特方法。这里不再赘述原因,给出几个结果:

方法一:

下面是利用.NET Framework平台优势实现Singleton模式的代码:

sealed class Singleton
{
   private Singleton();
   public static readonly Singleton Instance=new Singleton();
}

 

这使得代码减少了许多,同时也解决了线程问题带来的性能上损失。那么它又是怎样工作的呢?

注意到,Singleton类被声明为sealed,以此保证它自己不会被继承,其次没有了Instance的方法,将原来_instance成员变量变成public readonly,并在声明时被初始化。通过这些改变,我们确实得到了Singleton的模式,原因是在JIT的处理过程中,如果类中的static属性被任何方法使用时,.NET Framework将对这个属性进行初始化,于是在初始化Instance属性的同时Singleton类实例得以创建和装载。而私有的构造函数和readonly(只读)保证了Singleton不会被再次实例化,这正是Singleton设计模式的意图。

不过这也带来了一些问题,比如无法继承,实例在程序一运行就被初始化,无法实现延迟初始化等。

 

方法二:

既然方法一存在问题,我们还有其它办法。

public sealed class Singleton
{
  Singleton()
  {
  }

  public static Singleton GetInstance()
  {
    return Nested.instance;
  }
    
  class Nested
  {
    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Nested()
    {
    }

    internal static readonly Singleton instance = new Singleton();
  }
}

  

 

    java示例:

public class Singleton {

  private static Singleton instance = null;
  public static synchronized Singleton getInstance() {
      if (instance == null){
        instance = new Singleton();
        }
      return instance;   
    }

}

 

 

  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值