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类图中,使用带箭头的虚线表示这类关系,箭头指向被依赖的类。

相关推荐
科比不来it7 小时前
Go语言数据竞争Data Race 问题怎么检测?怎么解决?
开发语言·c++·golang
给大佬递杯卡布奇诺8 小时前
FFmpeg 基本API av_seek_frame函数内部调用流程分析
c++·ffmpeg·音视频
uxiang_blog8 小时前
C++进阶:重载类型转换
linux·开发语言·c++
moringlightyn9 小时前
c++11可变模版参数 emplace接口 新的类功能 lambda 包装器
开发语言·c++·笔记·其他·c++11·lambda·包装器
郝学胜-神的一滴9 小时前
使用Linux系统函数递归遍历指定目录
linux·运维·服务器·开发语言·c++·软件工程
会开花的二叉树10 小时前
C++微服务 UserServer 设计与实现
开发语言·c++·微服务
我星期八休息10 小时前
C++智能指针全面解析:原理、使用场景与最佳实践
java·大数据·开发语言·jvm·c++·人工智能·python
·白小白10 小时前
力扣(LeetCode) ——11.盛水最多的容器(C++)
c++·算法·leetcode
Code_Geo10 小时前
agent设计模式:第一章节—提示链
microsoft·设计模式·agent·模型
fsnine10 小时前
Python图形化界面——pyqt5教程
开发语言·python·qt