zoukankan      html  css  js  c++  java
  • C#设计模式—— 单例模式(简单的说)

    单例模式:确保一个类只有一个实例,并提供一个全局访问点。(定义)
    概念拆解:
    (1)确保一个类只有一个实例
    (2)提供一个访问它的全局访问点
    个人理解:
      一个类不被new,在类里的方法不被重复的new,在多线程调用实例时,确保只有一个实例在运行。
    生活中的例子:
      一个国家只有一个总统。
    简单的单例模式代码:
    /// <summary>
    /// 单例模式的实现
    /// </summary>
    public class Singleton
    {
    // 定义一个静态变量来保存类的实例
    private static Singleton uniqueInstance;
    
    // 定义私有构造函数,使外界不能创建该类实例
    private Singleton()
    {
    }
    
    /// <summary>
    /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
    /// </summary>
    /// <returns></returns>
    public static Singleton GetInstance()
    {
    // 如果类的实例不存在则创建,否则直接返回
    if (uniqueInstance == null)
    {
    uniqueInstance = new Singleton();
    }
    return uniqueInstance;
    }
    }
    》》在多线程中,需要确保一个实例。(我们可以使用线程锁lock来控制 )
     
       /// <summary>
        /// 单例模式的实现
        /// </summary>
        public class Singleton
        {
            // 定义一个静态变量来保存类的实例
            private static Singleton uniqueInstance;
    
            // 定义一个标识确保线程同步
            private static readonly object locker = new object();
    
            // 定义私有构造函数,使外界不能创建该类实例
            private Singleton()
            {
            }
    
            /// <summary>
            /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
            /// </summary>
            /// <returns></returns>
            public static Singleton GetInstance()
            {
                // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
                // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
                // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
                lock (locker)
                {
                    // 如果类的实例不存在则创建,否则直接返回
                    if (uniqueInstance == null)
                    {
                        uniqueInstance = new Singleton();
                    }
                }
    
                return uniqueInstance;
            }
        }
     
    》》多线程的“双重锁定”(目的:为了减少不必要的开销)
       /// <summary>
        /// 单例模式的实现
        /// </summary>
        public class Singleton
        {
            // 定义一个静态变量来保存类的实例
            private static Singleton uniqueInstance;
    
            // 定义一个标识确保线程同步
            private static readonly object locker = new object();
    
            // 定义私有构造函数,使外界不能创建该类实例
            private Singleton()
            {
            }
    
            /// <summary>
            /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
            /// </summary>
            /// <returns></returns>
            public static Singleton GetInstance()
            {
                // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
                // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
                // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
                // 双重锁定只需要一句判断就可以了
                if (uniqueInstance == null)
                {
                    lock (locker)
                    {
                        // 如果类的实例不存在则创建,否则直接返回
                        if (uniqueInstance == null)
                        {
                            uniqueInstance = new Singleton();
                        }
                    }
                }
                return uniqueInstance;
            }
        }

    简单模拟网站计数功能

         public class Singleton
        {
             private static Singleton instance;//静态实例
             private static readonly object locker = new object();//静态锁
             public int count = 1;
             private Singleton() {//构造函数
                 while (true)
                 {
                     Console.ReadKey();
                     count += 1;
                     Console.WriteLine(count.ToString());
                 }
             }
    
             public static Singleton GetInstance()//方法,方法中去实例化类.
             {
                 if (instance == null)
                 {
                     lock(locker)
                     {
                         if (instance == null)
                         {
                             instance = new Singleton();
                         }
                     }
                 }
                 return instance;
             }
        }

     在某个时候我只需要一个线程去处理事务,不想有多个实例时。例如我们建立一个数据库存取的管理类。类中有许多的方法。

        public class DBManager
        {
            private static DBManager uniqueInstance;//定义一个静态变量来保存类的实例
            private static readonly object locker = new object();//定义一个线程锁
            private static SQLiteHelp sqliteHelper;//实例化一个数据库连接
    
            #region 全局访问点
            private DBManager()
            {
                string dbPath = Application.StartupPath + "\Data.thl";
                sqliteHelper = new SQLiteHelp("data source=" + dbPath + ";Pooling=true;FailIfMissing=false");
            }
            /// <summary>
            /// 全局访问点
            /// </summary>
            /// <returns></returns>
            public static DBManager GetInstance()
            {
                if (uniqueInstance == null)
                {
                    lock (locker)
                    {
                        if (uniqueInstance == null)
                        {
                            uniqueInstance = new DBManager();
                        }
                    }
                }
                return uniqueInstance;
            }
            #endregion
    
            #region 文件列表操作
            /// <summary>
            /// 插入路径
            /// </summary>
            /// <param name="path">路径</param>
            /// <returns></returns>
            public bool InsertFilePath(string path)
            {
                string sql = "insert into RunInfoList (FilePath,Status) values ('" + path + "','停止')";
                var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
                if (affectedCount == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
    
            /// <summary>
            /// 插入路径
            /// </summary>
            /// <param name="serverId">游服ID</param>
            /// <param name="path">路径</param>
            /// <returns></returns>
            public bool InsertFilePath(int serverId,string path)
            {
                string sql = "insert into RunInfoList (ServerId,FilePath,Status) values ('"+serverId+"','" + path + "','停止')";
                var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
                if (affectedCount == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
    
            /// <summary>
            /// 删除
            /// </summary>
            /// <param name="path">路径</param>
            /// <returns></returns>
            public bool DeleteFilePath(string path)
            {
                string sql = "delete from RunInfoList where FilePath = '" + path + "'";
                var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
                if (affectedCount == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
    
            /// <summary>
            /// 更新最后的备份时间
            /// </summary>
            /// <param name="path">路径</param>
            /// <returns></returns>
            public bool UpdateTime(string path)
            {
                string sql = "update RunInfoList set LastBackupTime=datetime('now') where FilePath = '" + path + "'";
                var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
                if (affectedCount == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
    
            /// <summary>
            /// 获取文件列表
            /// </summary>
            /// <returns></returns>
            public List<FileListInfo> GetFileList()
            {
                string sql = "select * from RunInfoList";
                var reader = sqliteHelper.ReturnDataReader(sql);
                List<FileListInfo> fileList = new List<FileListInfo>();
                while (reader.Read())
                {
                    FileListInfo data = new FileListInfo();
                    if (!Convert.IsDBNull(reader["ServerId"]))
                    {
                        data.ServerId = Convert.ToInt32(reader["ServerId"]);
                    }
                    if (!Convert.IsDBNull(reader["FilePath"]))
                    {
                        data.FilePath = reader["FilePath"].ToString();
                    }
                    if (!Convert.IsDBNull(reader["Status"]))
                    {
                        data.Status = reader["Status"].ToString();
                    }
                    if (!Convert.IsDBNull(reader["LastBackupTime"]))
                    {
                        data.LastBackTime = reader["LastBackupTime"].ToString();
                    }
                    fileList.Add(data);
                }
                return fileList;
            }
    
            /// <summary>
            /// 更新ServerId
            /// </summary>
            /// <param name="path"></param>
            /// <returns></returns>
            public bool UpdateServerId(string path,string serverid)
            {
                string sql = "update RunInfoList set ServerId='"+serverid+"' where FilePath = '" + path + "'";
                var affectedCount = sqliteHelper.ExecuteNonQuery(sql);
                if (affectedCount == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            #endregion
    }

    说了单例模式的一些概念和代码,重要的是我们要怎么应用在实际的开发中?以下是我在博客园找到的关于单例的运用场景。

    1. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~ 
    2. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
    3. 网站的计数器,一般也是采用单例模式实现,否则难以同步。
    4. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
    5. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
    6. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
    7. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
    8. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
    9. HttpApplication 也是单位例的典型应用。熟悉ASP.NET(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.
     
    总结以上,不难看出:
      单例模式应用的场景一般发现在以下条件下:
      (1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
      (2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
     
    参考资料:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html
  • 相关阅读:
    linux下守护进程的创建
    【转】ps命令详解
    【转】适配器模式
    【转】设计模式六大原则(6):开闭原则
    【转】设计模式六大原则(5):迪米特法则
    【转】设计模式六大原则(4):接口隔离原则
    【转】设计模式六大原则(3):依赖倒置原则
    【转】设计模式六大原则(2):里氏替换原则
    网站会不会因为同IP网站被K而受到惩罚
    网页加载速度是否影响网站排名
  • 原文地址:https://www.cnblogs.com/annkiny/p/5946932.html
Copyright © 2011-2022 走看看