本系列所有文章来自李建忠老师的设计模式笔记,系列如下:
设计模式(一)面向对象设计原则
23种设计模式(二)组件协作之模板方法
23种设计模式(三)组件协作之策略模式
23种设计模式(四)组件协作之观察者模式
23种设计模式(五)单一职责之装饰模式
23种设计模式(六)单一职责之桥模式
23种设计模式(七)对象创建之工厂方法
23种设计模式(八)对象创建之抽象工厂
23种设计模式(九)对象创建之原型模式
23种设计模式(十)对象创建之构建器
23种设计模式(十一)对象性能之单件模式
23种设计模式(十二)对象性能之享元模式
23种设计模式(十三)接口隔离之门面模式
23种设计模式(十四)接口隔离之代理模式
23种设计模式(十五)接口隔离之适配器
23种设计模式(十六)接口隔离之中介者
23种设计模式(十七)状态变化之状态模式
23种设计模式(十八)状态变化之备忘录
23种设计模式(十九)数据结构之组合模式
23种设计模式(二十)数据结构之迭代器
23种设计模式(二十一)数据结构之职责链
23种设计模式(二十二)行为变化之命令模式
23种设计模式(二十三)行为变化之访问器
23种设计模式(二十四)领域规则之解析器

文章目录

  • 动机
  • 模式定义
  • 要点总结

  之前所述的方法都是在通过抽象的设计来实现松耦合的设计。面向对象很好地解决了“抽象”的问题,但是不可避免地要付出一定的代价。比如抽象里面有虚函数和继承,虚函数带来的内存的消耗还是比较多的。

  对于通常情况来讲,这些消耗都可以忽略不计,但是在某些情况下,面向对象所带来的成本必须谨慎处理。

动机

  在软件系统中,经常有这样一些特殊类,必须保证它们在系统中只存在一个实例,才能确保他们的逻辑正确性,以及良好的效率。

  如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?

  • Singleton.cpp
class Singleton{private:Singleton();Singleton(const Singleton& other);
public:static Singleton* getInstance();static Singleton* m_instance;
};Singleton* Singleton::m_instance=nullptr;//线程非安全版本
Singleton* Singleton::getInstance() {if (m_instance == nullptr) {m_instance = new Singleton();}return m_instance;
}

  上述这种实现在多线程的情况下并不安全。解决这种情况可以加锁,但是锁的代价太大,因为每次访问都会被锁。

//线程安全版本,但锁的代价过高
Singleton* Singleton::getInstance() {Lock lock;if (m_instance == nullptr) {m_instance = new Singleton();}return m_instance;
}

  加双检查锁(锁前锁后双检查)就可以避免上述这个问题:

//双检查锁,但由于内存读写reorder不安全
Singleton* Singleton::getInstance() {if(m_instance==nullptr){Lock lock;if (m_instance == nullptr) {m_instance = new Singleton();}}return m_instance;
}

  上述这种实现仍然会存在一些问题。线程是在指令层次抢时间片,也就是m_instance = new Singleton();这一行代码可能会先分配内存,然后把内存地址给m_instance,然后再执行构造器。这样的话就会存在问题,当线程1还没有执行构造函数,但是已经有了地址m_instance之后,另外一个线程进来发现m_instance不是nullptr就直接返回了这个地址。但是这个地址是不能用的,因为还没有调用构造器。

  解决办法:

//C++ 11版本之后的跨平台实现 (volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;Singleton* Singleton::getInstance() {Singleton* tmp = m_instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);//获取内存fenceif (tmp == nullptr) {std::lock_guard<std::mutex> lock(m_mutex);tmp = m_instance.load(std::memory_order_relaxed);if (tmp == nullptr) {tmp = new Singleton;std::atomic_thread_fence(std::memory_order_release);//释放内存fencem_instance.store(tmp, std::memory_order_relaxed);}}return tmp;
}

模式定义

  保证一个类仅有一个实例,并提供一个该实例的全局访问点。

要点总结

  Singleton模式中的实力构造器可以设置为protected以允许子类派生。

  Singleton模式一般不要支持拷贝构造函数和Clone接口,因为这有可能导致多个对象实例,与Singleton模式的初衷违背。

23种设计模式(十一)对象性能之单件模式相关推荐

  1. C++23种设计模式(1)-工厂方法模式

    C++常用的设计模式有23种. 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享 ...

  2. 23种设计模式,今天来聊聊模板模式,工厂方法模式,单例模式。

    23种设计模式,今天来聊聊模板模式,工厂方法模式,单例模式. 1. 随处可见的模板模式 2. 暗含讲究的工厂方法模式 3. 单例模式隐含的坑你能看到第几层? 视频讲解如下,点击观看: [干货篇]23种 ...

  3. 23种设计模式【全】 包含:模式定义 使用场景 实现步骤 优缺点 模式区别 UML类图 示例代码 注意项等

    23种设计模式(全) ***项目地址***:[GitHub](https://github.com/yjhroot/design-pattern) 声明 模式分类(3大类) 创建型模式(共5种) 结构 ...

  4. 23种设计模式(十四)模板方法模式(阁瑞钛伦特软件-九耶实训)

    常说的设计模式是23种设计模式,分为3大类: 创建型模式5种:工厂方法.抽象工厂.单例.建造者.原型 结构型模式7种:适配器.代理.桥接.装饰者.外观.享元.组合 行为型模式11种:模板方法.解释器. ...

  5. 23种设计模式(二十三)访问者模式(阁瑞钛伦特软件-九耶实训)

    常说的设计模式是23种设计模式,分为3大类: 创建型模式5种:工厂方法.抽象工厂.单例.建造者.原型 结构型模式7种:适配器.代理.桥接.装饰者.外观.享元.组合 行为型模式11种:模板方法.解释器. ...

  6. 23种设计模式(7):原型模式

    本文主要介绍设计模式中的原型模式. 现在电子账单越来越流行了,比如你的信用卡,到月初的时候银行就会发一份电子邮件到你邮箱中,说你这个月消费了多少,什么时候消费的,积分是多少等等,这是每个月发一次,还有 ...

  7. 23种设计模式(6):代理模式

    先看一个例子,是有关于打游戏杀怪兽的. //先定义一个游戏者接口 public interface IGamePlayer {//登陆游戏public void login(String user, ...

  8. 23种设计模式(15):备忘录模式

    定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样就可以将该对象恢复到原先保存的状态 类型:行为类 类图: 我们在编程的时候,经常需要保存对象的中间状态,当需要的时 ...

  9. C++23种设计模式(22)-中介者模式

    中介者模式:用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互.中介者模式的例子很多,大到联合国安理会,小到房屋中介,都扮演了 ...

  10. 23种设计模式之-----简单工厂(静态工厂)模式(SimpleFactory Pattern)

    这里引用 https://www.kailing.pub/PdfReader/web/viewer.html?file=24DesignPattern 讲解设计模式一文中的例子. 这个例子很形象而且通 ...

最新文章

  1. 让人又爱又恨的Mysql多表查询
  2. hadoop 1.2.1 安装步骤 伪分布式
  3. vue+vant 移动端H5 商城项目_01
  4. 计算机开机不正常运行,win7 64位旗舰版电脑开机启动不正常怎么办
  5. python 多线程读写文件_python多线程写入文件问题
  6. 《图解算法》第九章之动态规划
  7. 旋风解析磁力php,2018年免费引擎和正版旋风四核引擎棋力测试分析
  8. 编码(decode与encode)
  9. 在线全网音乐搭建源码_支持下载
  10. ​ZMC运动控制器SCARA机械手应用快速入门
  11. SylixOS移植Redis库总结
  12. Nginx的软件架构
  13. 程序员怎么接单赚外快,去这6个平台就可以了!
  14. 大学生活:计算机专业学生在大学四年内可以做些什么来丰富简历?
  15. 百度与吉利联合制造智能电动汽车;霍尼韦尔2020年度10大创新科技揭晓 | 美通企业日报...
  16. HBaseCon亚洲2018峰会盛大开幕 阿里带你洞悉HBase大数据生态最新发展和行业实践
  17. Attempted import error: ‘Redirect‘ is not exported from ‘react-router-dom‘ (imported as ‘Redirect‘)
  18. ios 11 屏幕适配问题!
  19. JDK的安装与环境变量配置详细教程
  20. ASP.NET商品进销存管理系统【附项目下载地址】

热门文章

  1. JavaScript验证表单大全【自用】
  2. web安全day2:NTFS安全权限
  3. HCIE-RS面试---STP拓扑变化过程
  4. 冯偌依曼计算机的基本原理是,软件《计算机组成原理》试卷 A
  5. Linux四剑客详解——grep
  6. python类中的self参数和cls参数
  7. SAP恭贺德国国家足球队夺冠!
  8. Git服务器的搭建和使用
  9. 如何在form初始化时自动隐藏FOLDER列
  10. SQLServer · 特性分析 · SQL Server 2012的分析函数未必都理解透了(2)