zoukankan      html  css  js  c++  java
  • c# 设计模式之单例模式

    单例模式:一个类在内存中只有一个对象(实例),并且提供一个可以全局访问或者获取这个对象的方法。

    这两天学的,写了个小例子,问了同事一些关于线程的问题,还有从网上查了一些资料。还犯了一些低级的错误。

    vs2017控制台输出文字乱码,从网上找了一些方法不管用,最后发现是自己新建项目选错模板了,选择了.NET CORE的模板,所以才会输出乱码,大家一定要吸取教训。

    直接上代码

    演示类,Person.cs

        public class Person
        {
            /// <summary>
            /// 实例化一个私有静态变量,存储类本身的实例
            /// </summary>
            private static Person _person  = null;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            private Person()
            {
                Console.WriteLine("构造了一个{0}",GetType().Name);
            }
          
            public static Person GetInstance()
            {
                if(_person == null)
                    _person = new Person();
                return _person;
            }    
        }

    客户端代码:

    {
      var person1 = Person.GetInstance();
      var person2 = Person.GetInstance();
      var person3 = Person.GetInstance();
    Console.WriteLine("person1 == person2:{0}", object.ReferenceEquals(person1, person2)); }

    输出结果:

    只输出了一次,两个对象引用相等。说明单例模式没问题。

     进阶:

     public class Person
     {
            /// <summary>
            /// 实例化一个私有静态变量,存储类本身的实例
            /// </summary>
            private static Person _person  = null;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            private Person()
            {
                Console.WriteLine("构造了一个{0}",GetType().Name);
            }
    
            public static Person GetInstance()
            {
                if (_person == null)
                    _person = new Person();
                return _person;
            }
    }

    客户端调用代码:

               {
                    Person person1 = null;
                    Person person2 = null;
                    Person person3 = null;
                    //多线程下可以输出多次
                    var thread1 = new Thread(() => { person1 = Person.GetInstance(); });
                    var thread2 = new Thread(() => { person2 = Person.GetInstance(); });
                    var thread3 = new Thread(() => { person3 = Person.GetInstance(); });
                    thread1.Start();
                    thread2.Start();
                    thread3.Start();
                    Thread.Sleep(1000);//等待子线程完成
                    Console.WriteLine("person1 == person2:{0}", object.ReferenceEquals(person1, person2));
                }

    输出结果:

    输出了多次,引用也不相等。说明多次实例化这个类,单例模式写的不完全正确,那让我们加上线程安全验证。

    继续进阶: 

     public class Person
     {
            /// <summary>
            /// 实例化一个私有静态变量,存储类本身的实例
            /// </summary>
            private static Person _person  = null;
    
            /// <summary>
            /// 作为锁的对象,使用私有的、静态的并且是只读的对象
            /// </summary>
            private static readonly object _obj = new object();
    
            /// <summary>
            /// 构造函数
            /// </summary>
            private Person()
            {
                Console.WriteLine("构造了一个{0}",GetType().Name);
            }
    
            /// <summary>
            /// 获取类唯一的实例对象
            /// </summary>
            public static Person GetInstance()
            {
                if (_person == null)//先判断是否为空
                {
                    lock (_obj)//再判断下是否有别的线程在使用
                    {
                        if (_person == null)//等其他线程使用完成后再判断是否为空
                        {
                            _person = new Person();
                        }
                    }
                }
                return _person;
            }
      }

    客户端调用代码:

                {
                    //使用锁,锁住的对象:使用私有的、静态的并且是只读的对象
                    Person person1 = null;
                    Person person2 = null;
                    Person person3 = null;
                    //多线程下可以输出多次
                    var thread1 = new Thread(() => { person1 = Person.GetInstance(); });
                    var thread2 = new Thread(() => { person2 = Person.GetInstance(); });
                    var thread3 = new Thread(() => { person3 = Person.GetInstance(); });
                    thread1.Start();
                    thread2.Start();
                    thread3.Start();
                    Thread.Sleep(1000);//等待子线程完成
                    Console.WriteLine("person1 == person2:{0}", object.ReferenceEquals(person1, person2));
                }

    输出结果:

    输出一次,引用相等,说明单例模式成功,线程安全已经加上。

    进阶2

    可以使用静态构造函数作为单例模式:

        public class Person
        {
            /// <summary>
            /// 实例化一个私有静态变量,存储类本身的实例
            /// </summary>
            private static Person _person  = null;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            private Person()
            {
                Console.WriteLine("构造了一个{0}",GetType().Name);
            }
            
            /// <summary>
            /// 静态构造函数,只执行一次
            /// </summary>
            static Person()
            {
                _person = new Person();
            }
            
            /// <summary>
            /// 获取类的实例
            /// </summary>
            public static Person GetInstance()
            {
                return _person;
            }
        }

    客户端代码:

             {
                    //使用锁,锁住的对象:使用私有的、静态的并且是只读的对象
                    //使用静态构造函数,在里面初始化person对象
                    Person person1 = null;
                    Person person2 = null;
                    Person person3 = null;
                    //多线程下可以输出多次
                    var thread1 = new Thread(() => { person1 = Person.GetInstance(); });
                    var thread2 = new Thread(() => { person2 = Person.GetInstance(); });
                    var thread3 = new Thread(() => { person3 = Person.GetInstance(); });
                    thread1.Start();
                    thread2.Start();
                    thread3.Start();
                    Thread.Sleep(1000);//等待子线程完成
                    Console.WriteLine("person1 == person2:{0}", object.ReferenceEquals(person1, person2));
                }

    输出结果:

     输出一次,引用相等,静态构造函数也可以作为单例模式实现的一种方法。

  • 相关阅读:
    telerik:RadGrid 在表格中编辑更新数据
    给已存在的表添加一个新字段
    Microsoft.Office.Interop.Excel 导出Excel
    反射导出 Excel
    aspx页面中获取当前浏览器url
    图片切换效果
    .net错误处理机制(转)
    javascript:void(0)知多少
    30款jQuery常用网页焦点图banner图片切换 下载 (转)
    Html.RenderPartial与Html.RenderAction区别(转)
  • 原文地址:https://www.cnblogs.com/dawenyang/p/7231006.html
Copyright © 2011-2022 走看看