Chapter1—设计模式基础

设计模式基础

1 面向对象基本概念

想要学好设计模式这一课程,我们需要了解一些面向对象编程的一些基本概念。

  • 封装(Encapsulation)

封装是面向对象编程的一个主要特征,它将对象的数据(属性)和操作这些数据的方法(行为)结合在一起,形成一个独立的对象。这样做的好处是可以隐藏内部的复杂性,只暴露有限的接口给外部使用。在Java中,通常通过设置成员变量为私有(private)来实现封装,并提供公共的方法(public methods)来访问和修改这些变量。

  • 继承(Inheritance)

继承允许新创建的类(子类)继承现有类(父类)的属性和方法。这意味着可以在现有类的基础上构建新的类,从而重用和扩展现有代码。在Java中,继承是通过关键字extends来实现的。

  • 多态(Polymorphism)

多态性是指允许不同类的对象对同一消息作出响应的能力。简单来说,就是允许使用父类类型的引用指向子类的对象。这样,同一个接口可以用来调用不同的实现方法,这些方法可能属于不同的类。

封装和继承的概念相对较为简单,多态相对来说比较复杂一点。

2 多态

C++多态(Polymorphism)允许使用基类指针或引用来调用子类的重写方法,从而使得同一接口可以表现不同的行为。

以下是多态的几个关键点:

虚函数(Virtual Functions)

  • 在基类中声明一个函数为虚函数,使用关键字virtual
  • 派生类可以重写(override)这个虚函数。
  • 调用虚函数时,会根据对象的实际类型来决定调用哪个版本的函数。

动态绑定(Dynamic Binding)

  • 也称为晚期绑定(Late Binding),在运行时确定函数调用的具体实现。
  • 需要使用指向基类的指针或引用来调用虚函数,编译器在运行时根据对象的实际类型来决定调用哪个函数。

纯虚函数(Pure Virtual Functions)

  • 一个包含纯虚函数的类被称为抽象类(Abstract Class),它不能被直接实例化。
  • 纯虚函数没有函数体,声明时使用= 0
  • 它强制派生类提供具体的实现。

多态的实现机制

  • 虚函数表(V-Table):C++运行时使用虚函数表来实现多态。每个包含虚函数的类都有一个虚函数表,表中存储了指向类中所有虚函数的指针。
  • 虚函数指针(V-Ptr):对象中包含一个指向该类虚函数表的指针。

使用多态的优势

  • 代码复用:通过基类指针或引用,可以操作不同类型的派生类对象,实现代码的复用。
  • 扩展性:新增派生类时,不需要修改依赖于基类的代码,只需要确保新类正确重写了虚函数。
  • 解耦:多态允许程序设计更加模块化,降低类之间的耦合度。

注意事项

  • 只有通过基类的指针或引用调用虚函数时,才会发生多态。
  • 如果直接使用派生类的对象调用函数,那么调用的是派生类中的版本,而不是基类中的版本。
  • 多态性需要运行时类型信息(RTTI),这可能会增加程序的开销。

程序示例

Worker 基类:

cpp 复制代码
class Worker
{
public:
    Worker() = default;
    virtual ~Worker() = default;

public:
    virtual void DoWork() = 0;
};

Coder类继承自Worker类:

cpp 复制代码
 class Coder: public Worker
{
public:
    Coder() = default;
    ~Coder() = default;

public:
    void DoWork() override;
};

void Coder::DoWork()
{
    qDebug() << "程序员写代码!";
}

Tester类继承自Worker类:

cpp 复制代码
class Tester: public Worker
{
public:
    Tester() = default;
    ~Tester() = default;

public:
    void DoWork() override;
};

void Tester::DoWork()
{
    qDebug() << "测试测试用例!";
}

测试函数:

cpp 复制代码
void TestPolymorphism()
{
    Worker* pWorker = nullptr;

    pWorker = new Coder();
    pWorker->DoWork();          // 调用Coder的DoWork方法
    delete pWorker;
    pWorker = nullptr;

    pWorker = new Tester();
    pWorker->DoWork();          // 调用Tester的DoWork方法
    delete pWorker;
    pWorker = nullptr;
}

有了多态的基础,我们还需要知道在面向对象编程中,我们类与类之间的一些常见关系,知道它们的UML类图怎么表示,学习设计模式本身不需要系统学习UML课程,但是基本的类图关系还是要会。

3 类间关系

设计模式中涉及到的常见的类之间的关系如下

  • 接口实现关系
  • 继承泛化关系
  • 不可分离组合关系
  • 可分离聚合关系
  • 关联关系
  • 依赖关系

接口实现关系

接口实现关系就是派生类必须重写接口中的所有方法,在UML类图中用"虚线+空心箭头"表示,其中箭头指向基类。

继承泛化关系

继承泛化关系就是常说的继承关系,派生类继承基类,基类被看作"一般设计",派生类被看作"特俗设计",因此继承泛化关系也被看作一般与特殊的关系,在UML类图中用"实线+实心箭头"表示,其中箭头指向基类。

不可分离组合关系

不可分离组合关系可以用整体和部分之间的关系来解释,部分是不能脱离整体单独存在的。部分对象与整体对象是不可分离的,一旦整体对象析构,部分对象就会随之消失,它们属于同一个生命周期。不可分离组合关系在UML类中用"实线+实心菱形"表示,其中实心菱形指向整体。

可分离聚合关系

可分离聚合关系也可以说成是整体与部分的关系,它与不可分离组合关系的区别是,这种整体与部分是可以分离的,也就是说部分是可以脱离整体单独存在的。UML类中用"实线+空心菱形"表示,其中空心菱形指向整体。

关联关系

关联关系就是一个类与另一个类在对象之间的联系,联系可以是双向的,也可以是单向的。在UML类图中,双向关联关系用没有箭头的实线表示,单向关联关系用"实线+箭头"表示,箭头指向被关联的类。


依赖关系

只有在一个类依赖另一个类中的方法时才存在依赖关系,一般将类作为参数传递,通过对方法的调用实现一个类访问另一个类的功能。在UML类图中,使用带箭头的虚线表示这类关系,箭头指向被依赖的类。

相关推荐
qq_392807955 小时前
C++ 多线程编程
开发语言·c++
CYRUS_STUDIO5 小时前
别再手工写 Hook 了!Python + Frida 一网打尽 SO 层动态注册 JNI 调用
android·c++·逆向
重启的码农5 小时前
云游戏技术之高速截屏和GPU硬编码 (5) 色彩空间转换器 (RGBToNV12)
c++·云计算·音视频开发
要做朋鱼燕5 小时前
【C++】Vector核心实现:类设计到迭代器陷阱
开发语言·c++·笔记·算法·职场和发展
学生小羊5 小时前
C++小游戏
开发语言·c++·游戏
企鹅chi月饼6 小时前
面试问题:c++的内存管理方式,delete的使用,vector的resize和reverse,容量拓展
c++·面试
hansang_IR6 小时前
【题解】洛谷P1776 宝物筛选 [单调队列优化多重背包]
c++·算法·动态规划·题解·背包·多重背包·单调队列
jndingxin6 小时前
c++多线程(1)------创建和管理线程td::thread
开发语言·c++·算法
SuperCandyXu6 小时前
洛谷 P3128 [USACO15DEC] Max Flow P -普及+/提高
c++·算法·图论·洛谷