C++设计模式——单例模式

导论:上次在面试的时候,面试官问及设计模式中的单例模式,什么是单例模式。在我把单例模式原理及两种实现方法道出,他问了一个问题,什么情况使用单例模式。在熟悉理论,并没有在实际开发过程中使用,这个问题问死了我。闲暇之余,重新的将这种简单且重要的软件设计模式总结。

单例模式:单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例。
单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
单例模式的优点:
1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例
2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
3.提供了对唯一实例的受控访问。
4.由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
5.允许可变数目的实例。
6.避免对共享资源的多重占用。
单例模式的缺点:
1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3.单例类的职责过重,在一定程度上违背了“单一职责原则”。
4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

单例模式的实现:
一.懒汉模式
对于懒汉版的单例模式,需要注意的线程安全的问题,在考略到多线程的问题,我们需要的就是加锁。如果不加锁,当多个线程同时对这个类进行实例时,这个类就同时完成多份实例出来的对象。在加锁的情况下,需要考略效率问题,但完成一次实例之后,再次获取时,不需要加锁,我们需要的是双重判断。我们在防止拷贝及赋值等处理时,只申明不定义,同时还需要的是防止在类外进行定义,要设置为私有。

    class Lock
    {
    public:
        Lock(mutex& m)
            :_mtx(m)
        {
            _mtx.lock();
        }

        ~Lock()
        {
            _mtx.unlock();
        }
    protected:
        Lock(const Lock&);
        Lock& operator=(const Lock&);
    private:
        mutex& _mtx;
    };

    class Singleton
    {
    public:
        static Singleton* Get()
        {
            if (Self == NULL)                  //提高效率
            {
                Lock lock(_mtx);               //线程安全
                if (Self == NULL)
                {
                    Self = new Singleton;
                }
            }
            return Self;
        }

    private:

        Singleton()
        {}

        //防拷贝
        Singleton(const Singleton& );
        Singleton& operator=(const Singleton&);
        static Singleton* Self;
        static mutex _mtx;
    };

    Singleton* Singleton::Self = NULL;

    mutex Singleton::_mtx;

二.饿汉模式
饿汉式单例类在类被加载时就将自己实例化,它的优点在于无须考虑多线程访问问题,可以确保实例的唯一性;从调用速度和反应时间角度来讲,由于单例对象一开始就得以创建,因此要优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲,饿汉式单例不及懒汉式单例,而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。

    class Singleton
    {
        static Singleton* Get()
        {
            assert(Self);
            return Self;
        }

        //static Singleton& Get2()
        //{
        //  static Singleton s;
        //  return s;
        //}
    protected:
        Singleton()
        {}
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);

        static Singleton* Self;
    };

    Singleton* Singleton::Self = new Singleton;

单例模式的应用
一些资源管理器常常设计成单例模式。
在计算机系统中,需要管理的资源包括软件外部资源,譬如每台计算机可以有若干个打印机,但只能有一个Printer Spooler, 以避免两个打印作业同时输出到打印机中。每台计算机可以有若干传真卡,但是只应该有一个软件负责管理传真卡,以避免出现两份传真作业同时传到传真卡中的情况。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。
需要管理的资源包括软件内部资源,譬如,大多数的软件都有一个(甚至多个)属性(properties)文件存放系统配置。这样的系统应当由一个对象来管理一个属性文件。
需要管理的软件内部资源也包括譬如负责记录网站来访人数的部件,记录软件系统内部事件、出错信息的部件,或是对系统的表现进行检查的部件等。这些部件都必须集中管理,不可整出多头。
这些资源管理器构件必须只有一个实例,这是其一;它们必须自行初始化,这是其二;允许整个系统访问自己这是其三。因此,它们都满足单例模式的条件,是单例模式的应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值