C++ 设计模式笔记——4. 行为型模式(一)
Chain of Responsibility
(责任链)
责任链模式是一种行为设计模式,将请求沿着处理者链进行发送。在收到请求后,每个处理者均可选择对请求进行处理,
或将其继续传递给下个处理者。
首先我们需要创建一个抽象处理者基类HandlerBase,对外提供了几个方法:
set_next:与另一个处理者建立后继关系,当前处理者可能把请求处理完成,也可能将请求传递给后继者;
handle_request:尝试处理请求,为了避免在责任链中出现死循环,使用哈希表记录下曾经出现过的处理者,处理过程有三种结果:
遇到了可以处理请求的对象,处理成功;
回到之前遇到的处理者,表明出现死循环,处理失败;
责任链查找到了尽头,即不存在后继者,处理失败。
HandlerBase还预留了几个接口:
can_handle:判断是否可以处理完成当前的请求,返回布尔值
handle:处理当前的请求
从基类HandlerBase继承得到各种类型的具体处理者(例如HandlerA、HandlerB和HandlerC),
它们分别实现了不同版本的can_handle和handle,不同类型的处理者 ...
C++ 设计模式笔记——3. 结构型模式
Adapter (适配器)
适配器模式是一种结构型设计模式,它使接口不兼容的对象能够相互合作。
假设我们已有一个现有类Adaptee,它提供接口specificRequest(),客户端希望调用接口类Target的request()方法,
两个接口无法直接相连,并且可能存在一些差异,例如函数参数顺序。
出于某些原因,我们无法更改旧有代码,那么可以选择在其中加上适配器Adapter:
适配器Adapter直接继承接口类Target,可以对客户端提供request()方法;
适配器Adapter将现有类Adaptee作为数据成员,在request()方法中实际调用Adaptee对象的specificRequest(),在传递过程中还需要处理一些差异,例如调整函数参数顺序。
示例代码如下 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748#include <iostream>#include <memory>#include <ut ...
C++ 设计模式笔记——2. 创建型模式
Factory Method (工厂方法)
工厂方法模式是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。
我们需要定义两个抽象类:产品基类Product和工厂基类Factory,后者提供创建产品的方法createProduct()。
具体产品(ProductA、ProductB)需要继承自产品基类Product。
每一个产品都需要提供配套的工厂(FactoryA、FactoryB),工厂需要继承自工厂基类Factory,对创建产品的方法提供不同的实现。
示例代码如下 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556#include <iostream>#include <memory>// 产品接口struct Product { virtual void describe() const = 0; virtual ~Product() = d ...
C++ 设计模式笔记——1. 概述
有必要学一下设计模式,虽然在大部分情况下都是基于Java语言来讨论设计模式,但是面向对象的思想对于各种语言都是通用的,这一系列笔记将使用C++进行讨论。
设计原则
通常设计模式遵循七个基本原则,如下文所示。有的教程中只有六个基本原则,不含单一职责原则。
单一职责原则
每个类应该只有一个职责,即该类只有一个引起变化的原因。
这样可以减少类之间的耦合,提高系统的可维护性。
与单一职责原则相违背的极端做法是使用上帝对象,它负责了太多的职责,了解了太多的信息,这会导致代码的修改和维护非常困难。
考虑一个情景,我们需要实现一个简单的文件管理类:读取文件内容并输出到控制台,向文件中写入指定内容,我们希望在读写操作的同时在控制台中输出日志。
不符合单一职责原则的例子如下 123456789101112131415161718192021222324252627282930313233343536373839#include <fstream>#include <iostream>#include <string>class FileManager ...
Fish Shell 配置笔记
记录一下关于fish的使用和配置。
概述
fish和zsh是最常见的两种用于替代默认bash的现代shell,两者的定位有点区别:
fish对用户友好,开箱即用,不需要复杂配置,缺点是语法与bash不兼容;
zsh兼容bash的语法,缺点是必须进行较复杂的配置,否则和bash使用体验差不多。
对这些shell的主题配置,通常都会基于oh-my-zsh、oh-my-fish以及pwsh的oh-my-pwsh这些美化工具进行,
但是鉴于fish的开箱即用特点,我决定不使用美化工具,默认的就可以了。
由于fish不兼容bash的语法,因此通常不建议将其作为默认shell使用,而是在登陆后手动开启fish
1fish
这样我们可以继续使用bash的.bashrc进行环境变量等配置,fish也会自动继承相应的配置。
日常操作中最好也是继续使用bash脚本,通过shebang的方式指定使用bash。
使用
fish默认支持实时更新的彩色显示,对于无效命令使用红色进行警告,有效命令则显示为蓝色,对于有效路径会显示下划线提示。
(这些默认行为都可以通过配置修改)
fish会自动给出命令提示,以灰色 ...
什么是高质量的代码
学习并整理一下个人的理解:什么样的代码是高质量的代码?
编程范式的历史与演变
简单回顾一下编程范式的历史与演变。
顺序编程
在早期编程中,人们采用的编程方式被称为顺序编程(非结构化编程)——程序按照上下文顺序执行指令,GOTO语句在其中发挥了重要作用,
它可以无条件地跳转到程序的任意部分。
GOTO语句的滥用导致了“意大利面条式代码”,使得程序变得难以理解和维护。为了克服GOTO语句带来的代码混乱,20世纪60年代Edsger
Dijkstra等人提出了结构化编程。
结构化编程
结构化编程的核心是控制结构,例如顺序、选择(如if、switch)、循环(如for、while)等结构,通过这些控制结构来组织代码,尽可能避免GOTO语句的使用。控制结构提高了代码的可读性和维护性,是现代编程语言的重要基础。
面向过程编程
面向过程编程是基于函数调用的编程范式,通过一系列过程(函数)的调用来组织代码,C语言是其中的典型代表。
面向过程编程的特点是数据与操作分离,这对于较小规模的程序没有问题,但是对于更大型的项目,就会遇到维护困难:难以通过函数管理复杂的数据和状态。
面向对象编程
为了应对面向过程 ...
MATLAB 代码格式化工具 MBeautifier
MATLAB内置的代码格式化实在是太垃圾了,VScode的MATLAB插件所提供的格式化也是一样的鸡肋,它们连最基本的缩进和空格都处理不好,
还是选择一个第三方工具MBeautifier来完成吧。
概述
MBeautifier是一个开源的MATLAB项目,已经几年没更新了,看了一下它的功能比较简单:读取xml配置文件,解析文本,处理缩进和空格等格式化问题。
其实用几个Python脚本也可以达到类似的效果,但是有现成的当然更好,而且用Python去格式化MATLAB代码有点滑稽。
使用
记录一下配置过程:
下载项目的压缩包,在本地解压(例如放在MATLAB安装位置附近),例如D:\ProgramHuge\MATLAB\MBeautifier-master
将路径D:\ProgramHuge\MATLAB\MBeautifier-master存储到MATLAB的path中
修改具体配置,配置文件为resources\settings\MBeautyConfigurationRules.xml,配置的修改可以查看README文件,我只修改了一处配置,确保所有的函数都会产生缩进,默认只对嵌套 ...
MATLAB 调用 Cpp 动态库
C/C++的动态库几乎可以被所有其它语言正常调用,MATLAB也不例外,这里简单记录一下MATLAB调用C++动态库的做法。
首先,我们简单创建一个动态库,由于我们的实验环境是Windows+MSVC,需要注意动态库的符号导出问题,动态库包括头文件demo.h和源文件demo.cpp
demo.h12345678910111213#pragma once#ifdef MY_EXPORTS#define MY_API __declspec(dllexport)#else#define MY_API __declspec(dllimport)#endifextern "C" {MY_API int add(int a, int b);MY_API double multiply(double a, double b);}
demo.cpp123456#define MY_EXPORTS#include "demo.h"int add(int a, int b) { return a + b; }double m ...
Euler方程组的Riemann问题精确解
Euler方程组是典型的双曲守恒律方程组,对于Euler方程组的一些记号和基本结论以及针对双曲守恒律问题的分析见前文。
Riemann问题是为探究双曲守恒律模型的间断问题所设置的模型,我们考虑一维Euler方程组的Riemann问题精确解求解。
\[
\begin{aligned}
\begin{pmatrix}
\rho \\ \rho u \\ E
\end{pmatrix}_t
+
\begin{pmatrix}
\rho u \\ \rho u^2 + p \\ u(E + p)
\end{pmatrix}_x
= 0,\,\,\,
E = \frac12 \rho u^2 + \frac{p}{\gamma-1}
\end{aligned}
\]
Riemann问题介绍
对于无界计算区域 \(x \in
\mathbb{R}\),Riemann问题指的是初值在\(x=0\)两侧取不同的常数值,在\(x=0\)存在一个间断,即
\[
\mathbf{U}(x,0) =
\left\{
\begin{aligned}
&\mathbf{U}_l, x < 0\\
& ...
USTC LaTeX 通过 Git 使用
USTC LaTeX
是主要支持在线使用的LaTeX平台,基于Overelaf开源版进行的开发,直接支持通过Git仓库同步的功能。
使用Git仓库时,我们可以利用本地的代码编辑器,这比使用浏览器上的编辑器要方便得多,因此记录一下对应的做法。
首先,从网站获取Git仓库链接,通常形如https://latex.ustc.edu.cn/git/xxxxxxx.git,主分支名称为master(这个似乎不可以修改)。
然后将其克隆到本地,并且重新取一个仓库名,例如 1git clone https://latex.ustc.edu.cn/git/xxxxxxx.git latex_test
由于项目的文件在平台上随时有可能被更改,在本地仓库对代码进行修改之后,远程推送很可能会出现推送失败的情况,对应的处理措施如下:
第一步,我们需要使用其它分支指向本地仓库的最新版本(确保本地的修改不会丢失)
第二步,执行如下命令,确保本地仓库与远程仓库的主分支最新版本保持一致
123git fetch --allgit reset --hard origin/mastergit pull
第三步,在本 ...