罗剑锋的C++实战笔记
罗剑锋
奇虎360技术专家,Nginx/OpenResty开源项目贡献者
立即订阅
3724 人已学习
课程目录
已完结 30 讲
0/4登录后,你可以任选4讲全文学习。
课前导读 (2讲)
开篇词 | 把C++从“神坛”上拉下来,这次咱这么学
免费
课前准备 | 搭建实验环境
概论 (5讲)
01 | 重新认识C++:生命周期和编程范式
02 | 编码阶段能做什么:秀出好的code style
03 | 预处理阶段能做什么:宏定义和条件编译
04 | 编译阶段能做什么:属性和静态断言
05 | 面向对象编程:怎样才能写出一个“好”的类?
语言特性 (5讲)
06 | auto/decltype:为什么要有自动类型推导?
07 | const/volatile/mutable:常量/变量究竟是怎么回事?
08 | smart_ptr:智能指针到底“智能”在哪里?
09 | exception:怎样才能用好异常?
10 | lambda:函数式编程带来了什么?
标准库 (4讲)
11 | 一枝独秀的字符串:C++也能处理文本?
12 | 三分天下的容器:恰当选择,事半功倍
13 | 五花八门的算法:不要再手写for循环了
14 | 十面埋伏的并发:多线程真的很难吗?
技能进阶 (4讲)
15 | 序列化:简单通用的数据交换格式有哪些?
16 | 网络通信:我不想写原生Socket
17 | 脚本语言:搭建高性能的混合系统
18 | 性能分析:找出程序的瓶颈
总结篇 (5讲)
19 | 设计模式(上):C++与设计模式有啥关系?
20 | 设计模式(下):C++是怎么应用设计模式的?
21 | 知识串讲(上):带你开发一个书店应用
22 | 知识串讲(下):带你开发一个书店应用
期末测试 | 这些C++核心知识,你都掌握了吗?
结束语 (1讲)
结束语 | 路远,未有穷期
轻松话题 (4讲)
轻松话题(一) | 4本值得一读再读的经典好书
轻松话题(二) | 给你分享我的工作百宝箱
轻松话题(三) | 提高生活质量的App
轻松话题(四) | 真正高效的生活,是张弛有度
罗剑锋的C++实战笔记
15
15
1.0x
00:00/00:00
登录|注册

20 | 设计模式(下):C++是怎么应用设计模式的?

罗剑锋 2020-06-20
你好,我是 Chrono。
上节课,我谈了设计模式和设计原则。今天,我就具体说说,在 C++ 里,该怎么应用单件、工厂、适配器、代理、职责链等这些经典的设计模式,用到的有 call_once()、make_unique()、async() 等 C++ 工具,希望能够给你一些在实际编码时的启发。
(在接下来学的时候,你也可以同时思考一下它们都符合哪些设计原则,把设计模式和设计原则结合起来学习。)

创建型模式

首先来看看创建型模式,它隐藏了类的实例化过程和细节,让对象的创建独立于系统的其他部分
创建型模式不多,一共有 5 个,我觉得最有用的是单件和工厂
单件很简单,要点在于控制对象的创建数量,只能有一个实例,就像是公司的 CEO 一样,有且唯一。
关于它的使用方式、应用场景,存在着一些争议,但我个人觉得,它很好地体现了设计模式的基本思想,足够简单,可以作为范例,用来好好学习模式里的各个要素。
关于单件模式,一个“老生常谈”的话题是“双重检查锁定”,你可能也有所了解,它可以用来避免在多线程环境里多次初始化单件,写起来特别繁琐。
使用第 14 讲里提到的 call_once,可以很轻松地解决这个问题,但如果你想要更省事的话,其实在 C++ 里还有一种方法(C++ 11 之后),就是直接使用函数内部的 static 静态变量。C++ 语言会保证静态变量的初始化是线程安全的,绝对不会有线程冲突。比如:
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《罗剑锋的C++实战笔记》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(5)

  • 有学识的兔子
    1、可以根据需要,通过不同的参数定制化,产生不同的对象;同时还可以对参数类型范围进行检查。
    2、相同之处在于都是对于原始类或对象的二次封装;
    不同在于:
    适配器是为了解决接口不兼容的问题,提供新接口来间接改造原始接口;
    装饰器:与原始类继承同样的父类,为原始类提供了额外增强的功能接口,且可以嵌套多个装饰器;
    代理:个人感觉和装饰器非常像,但代理的作用更偏向于类或对象本身功能之外的能力,例如统计调用次数/运行时间,有点管理原始类的意思。

    作者回复: 对,总结的很好。

    很多设计模式的结构都很相似,因为用的都是对象组合技术,但区别就在于它们的使用方式、目的、用途。

    2020-06-21
    2
  • this_is_for_u
    感谢老师,这篇文章读下来收获还是蛮多的,但文中提到静态变量初始化是线程安全得,前提貌似应该加个c++11后,避免争议

    作者回复: 感谢提醒,稍后会联系编辑做个补充。

    2020-06-20
    2
  • lckfa李钊
    又提起了单例模式,我个人是很反对单例模式的,其缺点大于优点:破坏了程序的封装,可以随便传来传去的多可怕,有全局变量的全部缺点(如果你需要使用全局变量,这说明你的设计有很大的问题),违背了单一职责原则,难以单元测试,依赖不清等;实在要使用单例模式的话,一定要注意原则:如果你使用单例是因为某个类的实例不能超过一个,那么这通常是可以的。如果使用它是因为singleton是一个全局可访问的对象,它可以让您避免考虑与其他对象如何相互通信,以及每个对象负责什么,那就是你用错了!

    适配器类 继承于某个类,然后对这个类进行接口改造,使之能适配另一个类的对其调用;

    装饰模式在不改变对象接口的前提下强化对象的功能;

    与适配器模式提供不同的接口以适配调用不同,代理模式则是提供相同的接口,代替宿主完成某些功能,

    作者回复: 说的很好,单件易学,用起来简单,所以就很容易被滥用,这个是需要特别注意的。

    但从学习设计模式的角度来看,它是一个很好的范例。

    2020-06-20
    1
  • 有一个感想。。所有设计模式,都是为了隔离变化,所谓的设计模式的教程其实在教我们:
    编程时,哪些地方要注意变化,如何应对变化。

    作者回复: 理解的非常对,设计模式的一个核心思想就是引入中间层,隔离变化,尽量减少代码的变动。

    2020-07-03
  • 骥千🇨🇳
    老师,问一个非继承情况虚函数的问题,如下代码,
    #include <iostream>
    class A {
    public:
    void f1() { printf("A::f1\n"); }
    virtual void f2() { printf("B::f2\n"); }
    };
    class B {
    public:
    virtual void f1() { printf("B::f1\n"); }
    virtual void f2() { printf("B::f2\n"); }
    };
    int main() {
        B obeject;
        A* p = (A*)&obeject;
        p->f1();
        p->f2();
        return 0;
    }
    编译执行结果( ubuntu20.04, g++ 9.3.0 ):
    A::f1
    B::f1
    老师能解释一下为什么是这样吗

    作者回复: 这个应该是类型强转了,太hack了,不建议这么用,没什么意义。

    2020-06-21
    2
收起评论
5
返回
顶部