• [设计模式]单例模式


    引言

    做为已经开发9年多的我,最近感觉有点迷茫,技术更新太快,有点跟不上这么快的节奏,在开始工作时,一直也听领导说23种设计模式,当时也看了视频,看完也没有太大的收获,在工作中有的时候也是为了把设计模式强加到代码中,最近在看设计模式时,确实有了更深刻的理解。在此我还是建议热爱编程的同行,“如果连自己喜欢的工作,都做不好,那么活着就太空虚了,男人么就应该对自己恨一点。如果你现在没有得到你想要的生活,只能说明你对自己还不够狠”。言归正传,说说今天的单例模式。

    单例模式定义

    单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

    单例模式类图

     (类图来自:http://www.cnblogs.com/zhili/p/SingletonPatterm.html,这里借用一下)

    常见的单例模式

    /// <summary>
    /// 饿汉式
    /// </summary>
    public sealed class Singleton
    {
    /// <summary>
    /// 私有构造函数
    /// </summary>
    private Singleton()
    {

    }
    private static readonly Singleton _Instance = new Singleton();//定义私有的静态变量
    public static Singleton Instance
    {
    get
    {

    return _Instance;
    }
    }
    }

    优点:
      1.线程安全 
      2.在类加载的同时已经创建好一个静态对象,调用时反应速度快。
           3.通过sealed修饰类,阻止派生类的出现,因为派生可能会增加实例。
    缺点:
      资源效率不高,可能GetInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化。
     

    /// <summary>
    /// 懒汉式
    /// </summary>
    public sealed class Singleton
    {
    /// <summary>
    /// 私有构造函数
    /// </summary>
    private Singleton()
    {

    }
    private static Singleton _instance = null;
    private static readonly object obj= new object();
    public static Singleton GetInstance
    {
    get
    {
    if(_instance==null)
    {
    lock(obj)
    {
    if(_instance==null)
    {
    _instance = new Singleton();
    }
    }
    }
    return _instance;
    }
    }
    }

    优点:

    1:懒汉式面临线程安全的问题,通过双重锁定这样的处理才可以保证安全。
    2:单例可以 被延迟加载。
     
     
     
    应用场景:
    数据库操作类不宜使用singleton模式
    不要将数据库连接做成单例,因为一个系统可能会与数据库有多个连接,并且在有连接池的情况下,应当尽可能及时释放连接。Singleton模式由于使用静态成员存储类实例,所以可能会造成资源无法及时释放,带来问题。
     
    做项目做的多了,所以考虑问题的方向也不一样了。以前刚开始只是以实现功能为目的,美观、实现方式、代码逻辑、执行效率等等,几乎不考虑。
    然而要想成为合格的软件设计师,软件的设计就必须全面周到,不仅仅只是考虑如何开发,更多的要考虑软件的发展和维护。
    所以平时的学习中多思考多理解是非常重要的。
    在学习DRP中,我们都知道王勇把业务逻辑层(Manager、servlet)都几乎做成的单例模式。我当时就思考为何他要这么做呢?
    渐渐的我明白了,而且是切身的理解了。
    在用.net开发web项目的时,在UI层我们要实例化BLL层的类,然而正因为是web开发,如果按照咱原来的写法(如下)
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
                News news = new NewsManager().SelectById(newsid); //News:新闻实体类,为Model层。 NewsManager:BLL层的类
        }
    }
    那么客户端只要与服务器需要交互一次就要执行一次Page_Load事件【因为与服务器交互后客户端浏览器会刷新页面】,那么就要实例化一次NewsManager(),这还仅仅是Page_Load的事件,往往还会有别的事件,比如按钮单击事件,因为UI层与BLL层的交互是非常平凡的。
    试想下这么多次重复的New的次数,是多么的浪费资源啊,即便把NewsManager设置成该页面的全局变量,还是免不了每刷新一次就实例化一次的弊端。
     
    所以把BLL层的类做成单例模式是出于对服务器资源优化的一个应用。
    关于单例模式的应用,我目前了解到的有:配置文件、打开窗口、工厂模式的工厂类、再有就是今天说的BLL层管理类。
    如果各位还有对于单例模式应用和技巧的见解还请多多请教
     
     
    BO层为什么设计为单例模式?
    1、首先要理解每一个BO实例是用来处理用户的一类请求操作的,即然是用来处理一类操作,那么所有的操作都可以用一个实例来完成即单例,只要不存在实例变量,那么就不会发生线程安全的问题。此时如果设计为多例的,并且不存在实例变量的情况,那么新实例和旧实例是没有任何区别的,都是执行同一类操作,处理用户的同一类请求。那么这时多实例只会占用更多的内存空间,没有任何益处。
     
    2、理解线程栈的问题。对于用户的每一次请求操作,都有一个线程来负责该用户的请求处理,那么这个线程在处理用户业务的同时,会在内存中分配一段内存区域,该内存区域存放了用户所调用的方法中的变量,我们称该内存区域为线程栈,线程栈中除了存有方法中的局部变量外,还持有调用该方法的单实例对象的一个引用。因为每一个线程栈都存储了当前单实例对象对应方法中局部变量的不同版本,那么这样每一个线程的方法操作都不会影响其他线程的方法操作,所以不存在线程安全的问题了。
     
    介绍了单例,有些人可能感觉静态类也可以完成上面的应用场景,再次我在这总结一下单例和静态类的区别,以供大家学习
     
    观点一:(单例)
    单例模式比静态方法有很多优势:
    1::单例可以继承类,实现接口,而静态类不能(可以集成类,但不能集成实例成员);
    2:单例可以被延迟初始化,静态类一般在第一次加载是初始化;
    :3::单例类可以被集成,他的方法可以被覆写;
    最后,或许最重要的是,单例类可以被用于多态而无需强迫用户只假定唯一的实例。举个例子,你可能在开始时只写一个配置,但是以后你可能需要支持超过一个配置集,或者可能需要允许用户从外部从外部文件中加载一个配置对象,或者编写自己的。你的代码不需要关注全局的状态,因此你的代码会更加灵活。
     
    观点二:(静态方法)静态方法中产生的对象,会随着静态方法执行完毕而释放掉,而且执行类中的静态方法时,不会实例化静态方法所在的类。如果是用singleton,   产生的那一个唯一的实例,会一直在内存中,不会被GC清除的(原因是静态的属性变量不会被GC清除),除非整个JVM退出了。这个问题我之前也想几天,并且自己写代码来做了个实验。
     
    观点三:(Good!)
    由于DAO的初始化,会比较占系统资源的,如果用静态方法来取,会不断地初始化和释放,所以我个人认为如果不存在比较复杂的事务管理,用singleton会比较好。个人意见,欢迎各位高手指正。  
    http://blog.csdn.net/v1v1wang/article/details/5511756
    -----------------------------------------------------------------------------------------------------------
     
    这里暂且把单例模式限定为不是全用静态函数实现的。
    1。使用的方便性:如果需要初始化工作,单例模式可以在构造函数里面完成,全静态函数的类需要一个额外的函数来完成初始化工作,而且使用者如果没有调用这个initialize函数,那么后续的操作就会有问题,构造函数会被默认调用,所以使用起来比较简单,对使用者做出了最少的假设。
    2。初始化时机:单例模式初始化比较灵活,可以在需要的时候初始化,而全静态函数必然导致成员全为静态成员,静态成员是在编译时就初始化好了。如果初始化成本比较昂贵,并且程序里面未必一定使用这个类,那这将是单例模式的一个很大优势。顺便说一下全局变量,全局变量的初始化顺序是未指定的。
    例如 全局变量int a; int b;编译器是先初始化a还是先初始化b?我想大家只能靠猜,或者在某个编译器上实验一下给出答案,一旦要是有个新编译器,结果又会是什么样子呢?
    3。最重要的区别:单例模式可以有多态,而全静态的类不能支持多态。
     
    总结:
    单例保证一个类只有一个实例,并提供对外的只有一个全局访问点。
     
    第一次写随笔,里面可能有些是在网上是借鉴,以此总结,便于自己记忆,如果可以给其它带来帮助的,就请大家看过,别用搬砖就可以了!!!!!!
  • 相关阅读:
    Debian9 挂载本地ISO当镜像源
    debian9使用ls命令显示文件和文件夹颜色
    debian无法使用netstat
    debian9修改MariaDB用户密码和配置
    python2安装mysqlclient报错EnvironmentError: mysql_config not found
    debian9部署python2虚拟环境
    Debian9安装MariaDB
    Debian9配置网络源
    向日葵远程按键失灵
    Debian9修改时区
  • 原文地址:https://www.cnblogs.com/sjkzy/p/7101777.html
Copyright © 2020-2023  润新知