![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a3afa1556f282b002b98f46a1735a1af.gif#pic_center)
📄前言
你可听说过只能在堆上创建的类、无法被拷贝的类、甚至是不能继承的类,如果你从未听闻过这样的奇妙的类设计,不妨点进本篇文章,来进入学习设计模式的第一步。
🌻特殊类的设计
当你看到这些要实现的特殊类,可能会感到困惑,为什么需要做出这种看似没有任何意义的类,此时不妨自己动手来实现一下它们,这些看似无用的设计,其实正是通向设计模式的第一步。
无法被继承的类
class NonInherit final //c++11中,直接使用final即可
{
NonInherit() {}
};
class NonInherit //c++98
{
private:
NonInherit(){} //私有构造函数即可阻止类被继承
}
只能在堆开辟空间的类
限制类的实例只能在堆上创建,可以通过构造函数私有化,然后通过一个静态的函数来创建类。
class HeapOnly
{
public:
static HeapOnly* creat() //静态函数来返回地址
{
return new HeapOnly;
}
private:
HeapOnly() {}; //设为私有
HeapOnly(const HeapOnly&) = delete;
};
无法被拷贝的类
防止类的对象被拷贝,可以通过删除拷贝构造函数和赋值运算符来实现。
class Noncopy
{
public:
Noncopy() {}
Noncopy &operator=(const Noncopy &) = delete; //也可设为私有
Noncopy(const Noncopy &) = delete;
};
只能在栈开辟空间的类
只要在类内把拷贝函数和赋值函数给设为私有或者使用delete(c++11)即可做出在栈开辟空间的类。
class StackOnly
{
public:
void* operator new(size_t) = delete;
void operator delete(void*) = delete;
static StackOnly create()
{
return StackOnly();
}
private:
StackOnly() {}
};
🌺单例模式
单例模式是一种常用的设计模式,其核心是确保程序中只能一个类只能拥有一个实例,从而实现资源重复利用性,减少性能的损耗。
有了上方特殊类的创建思路,就能更理解饿汉模式与懒汉模式
饿汉模式
饿汉模式,在程序加载类的时候就马上加载实例,这样一来就保证了实例的唯一性。
优点:
- 没有线程安全问题,因为在线程开始就被创建。
- 实现简单。
缺点:
- 可能会造成资源浪费,特别是在还没有用到实例的时候。
- 无法控制类的加载顺序,因为在程序加载时就运行,所以会拉慢程序加载速度。
class SingletonEager // 饿汉模式,正如其名一拿到资源就吃掉
{ // 优点:简单、
public: // 缺点:可能会造成资源的浪费,没有使用的情况
static SingletonEager &getInstance()
{
return _instance;
}
private:
SingletonEager(){};
SingletonEager(const SingletonEager &) = delete;
SingletonEager &operator=(const SingletonEager &) = delete;
static SingletonEager _instance;
};
SingletonEager SingletonEager::_instance;
懒汉模式
懒汉模式指的是在需要用到实例的时候再创建,以此来保证资源不被浪费。
优点:
- 减缓内存压力,如果没有用到实例则内存不会被分配。
- 加载速度较快。只有在使用时才被创建。
缺点:
- 线程安全问题:如果有多个线程同时访问类,需要自己保证资源不会被同时访问,出现二义性问题。
- 相比于饿汉模式,实现比较复杂。
class SingletonLazy // 懒汉模式,在需要使用到实例的时候再创建实例,杜绝了资源浪费。
{ // 优点:没有线程安全问题,杜绝资源浪费
public: // 缺点:实现较为复杂
SingletonLazy(const SingletonLazy &) = delete;
SingletonLazy &operator=(const SingletonLazy &) = delete;
static SingletonLazy *getInstance()
{
if(_instance == nullptr)
{ // 双重检查来减少锁的使用
std::lock_guard<std::mutex> lock(_mtx);
if (_instance == nullptr)
{
_instance = new SingletonLazy;
}
}
return _instance;
} // lock_guard 会自动释放 RAII
private:
SingletonLazy(){};
static SingletonLazy *_instance;
static std::mutex _mtx;
};
std::mutex SingletonLazy::_mtx; //静态成员需要初始化
SingletonLazy *SingletonLazy::_instance = nullptr;
📓总结
设计模式是前人总结出来的开发模板,每一个程序员都应该对它们有所了解,设计模式大致分为三类:创建型、结构型、行为型,本篇介绍了创建型的单例模式,但细算设计模式,一共有23种之多,这些设计模式让我们日后再谈。
单例模式类型 | 饿汉模式 | 懒汉模式 |
---|---|---|
优点: | 在程序启动时就完成了单例的初始化,保证了线程安全。实现简单。 | 单例实例在需要时才被创建,可以节省资源。对于资源消耗较大的单例,或者在初始化过程中需要依赖参数的情况下非常有用。 |
缺点: | 如果程序启动后,单例未被使用,则会造成资源的浪费。初始化单例的过程可能会增加应用程序启动时间。 | 需要在多线程环境下确保线程安全,实现相对复杂,可能会影响性能 |
![](https://i-blog.csdnimg.cn/blog_migrate/6978e059d51da817bf235e35f931e580.gif#pic_center)