2024年7月

单例模式:一个项目中,全局范围内,某个类的实例有且仅有一个,通过这个单例向其他模块提供数据的全局访问。

// 嵌入知识点:使用C++ 11新特性delete删除构造函数、拷贝函数、移动操作符
class A
{
public:
    A() = delete;
    A(const A & t) = delete;
    A& operator=(const A & t) = delete; // 删除赋值操作符
}

// 单例模式例子:使用C++ 11新特性default,修改构造函数和拷贝函数的访问权限
class A
{
public:
    static A* getInstance()
    {
        return m_instance;
    }

protected:
    A() = default;
    A(const A & t) = default;
    static A* m_instance; // 静态变量不能在类的内部初始化,初始化需要到外部
}
A* A::m_instance = new A; // 全局初始化时在A作用域下可以访问到A的m_instance和A()

任务队列:将一个一个的任务作为函数,装入队列这样的容器中,根据其先进先出的特性,使程序可以按照某种次序依次执行函数。典型例子如QT的QApplication::exec()事件循环。

单一职责原则:每个类做专一的功能,多个功能由多个类完成。
开放封闭原则:开放指类和模块、函数可扩展,即对于每个实体类都做一个抽象类,那就可以保证,每次需要扩展一个类的时候只需要实现一个类,而其他依赖它的类无需改动。
例子A,小明用铁锅炒蔬菜,这里一共有三个类:小明、铁锅、蔬菜,小明使用到了铁锅、铁锅里面装有蔬菜,即小明依赖了铁锅,蔬菜依赖了装它的容器铁锅,若此时需要将铁锅换成不粘锅,则不仅要新写不粘锅类,还需要将原本引用铁锅的蔬菜、小明处的代码全都改成不粘锅,这显然是扩展性差的体现。正确的设计代码结构的方式是将小明抽象为一个类(人),铁锅、不粘锅抽象为一个类(烧菜的容器)、蔬菜抽象为一个类(食物),然后将各种实体类继承于这些抽象类,这样的好处是当需要将铁锅换成不粘锅时,只需新写一个继承装菜容器这一抽象类的不粘锅类即可,而无需改动引用它的地方。
封闭指的是尽量不修改原有的类,若要修改,尽量采取增量修改的方式,扩充类或者扩充成员函数。
依赖转换原则:1. 高层模块不应该依赖于低层模块,高层模块和底层模块都应该有它的抽象;例子A就是一个符合该条的例子;因此,在设计结构的时候,高层不直接调用底层,而在两者之间封一层抽象类,高层调用抽象类的接口,从而调用到底层的模块;2. 抽象不应该依赖细节,细节应该依赖抽象。
里氏代换原则:子类类型必须能够替换掉它们的父类类型,抽象出来的父类能符合子类的共性特征。若代码结构不满足里氏代换原则,也就不满足依赖转换原则的第二条。

类与类之间的关系

继承关系(泛化关系):带空心三角形的实线表示,箭头指向父类。继承关系可以继承非抽象类也可继承抽象类。
关联关系:一个类作为另一个类的成员变量。可分三类:单向关联、双向关联、自关联(即链表)。带箭头实线表示,指向被关联的一方,单向关联一个箭头、双向关联两边都带箭头、自关联自己指向自己。
聚合关系:整体与部分的关系。例如:汽车由引擎、轮胎、车灯等组成,森林由植物、动物、水、阳光等组成。关系比较松散,当森林类被析构时,引擎、轮胎、车灯类不会被析构,即引擎、轮胎、车灯可以脱离整体而单独存在。用带空心的菱形的直线表示,菱形指向整体。
组合关系:整体与部分的关系。例如:头由嘴巴、鼻子、耳朵、眼睛构成,树由树根、树干、树枝、树叶构成。组成的部分对于整体来说缺一不可。析构整体的时候需要将部分全都析构。用带实心菱形的直线表示,菱形指向整体。
依赖关系:是一种使用关系。例如:将一个类的对象作为另一个类中方法的参数,在一个类的方法中将另一个类的对象作为其的局部变量,在一个类的方法中调用了另一个类的静态方法。用带箭头的虚线来表示,箭头指向被依赖的一方。
关系的紧密程度:继承>组合>聚合>关联>依赖