程序语言有设计模式吗



在我的经验中,我经常看到一些设计模式,比如访客模式、策略模式,。。。在Java等面向对象的语言中。。。但我在像C这样的过程语言中没有看到太多模式……我想知道这些模式是否存在于过程语言中?

过程语言确实有设计模式。但由于程序方法通常被忽视,而倾向于基于类的面向对象方法,因此它们并没有得到广泛的认可。

我用C语言开发高性能软件,有几种重复出现的模式。因此,我将提供一些我经常看到的模式。

处理

这就是过程编程中封装的方式。构造函数不返回结构或对象。但是句柄:它通常是一个不透明的指针,或者只是一个整数。你不能对它毫无兴趣,因为它只是一个数字。细节被完全隐藏了。但是您可以将这个句柄传递给处理它的函数:

示例:

  • 在Windows上,CreateWindow函数返回HWND。它是一个窗口的句柄,可以传递给ShowWindow、DestroyWindow等其他函数
  • 在Linux上,打开系统调用。它返回just和int。这是一个文件句柄

上下文

在过程语言中,对象通常被称为上下文。上下文是一个结构,它包含某些系统的状态,就像对象的成员一样。在OOP中,您编写object.method(parameter)。在过程编程中,您可以编写function(addressOfContext, parameter)。内部函数直接使用上下文结构,而公共函数只获取句柄,实现将其解析为实际的上下文结构。

回调

或者函数指针。函数的用户传递其函数的地址以将自定义行为添加到系统中。多态性是如何在过程编程中实现的。这允许编写通用函数。

一个值得注意的例子是qsort C函数。这采用元素数组的地址。获取一个元素的大小和数组中的元素数量,以及执行比较的比较器函数。这是一个完全通用的实现,允许对所有类型的数据进行排序。

设置结构

当一个函数可以通过多种方式进行参数化时。通常使用设置结构。规范通常要求这些结构在默认情况下为零填充,并且只填充相关的成员。如果某些成员是相互排斥的,那么他们就被置于一个联盟中。此类设置结构的典型示例是WinAPI中的WNDCLASS。

可变大小数据

这是一个C模式,而不是一般的设计模式。有时,对象可能包含任意大小的二进制有效载荷。这种模式通常发生在从可能包含几种类型的数据块的二进制文件中读取数据时。这是由这样一个结构完成的。

typedef struct
{
int someData;
int otherData;
int nPayloadLength;
unsigned char payload[1];
} VariableSized;

在代码中完成以下操作:

VariableSized *vs = malloc(sizeof(VariableSized) + extraLength);

这会分配比结构更大的内存,为可变长度的有效负载留出空间。其第5个字节可以被例如vs->payload[4]访问。

这样做的优点是可以在一个free调用中释放整个对象。它保证在内存中有一个连续的块。因此,它比在堆中的其他地方分配相应的缓冲区更好地利用了缓存。

OOP设计模式的程序对应物

OOP模式在过程语言中从来不会以其名称调用。所以我只能在这里猜测。

创建模式

  • 抽象工厂:抽象工厂通常是单例。在这种情况下,根本不使用此模式,而是使用条件编译。否则,设置提供创建功能的结构
  • Builder:使用设置结构
  • 工厂方法:回调用于创建
  • 懒惰初始化:在C++中,静态局部变量用于此目的。在C中,您可以在性能不关键的地方使用if (!initialized) { initialize(); initialized = 1; }模式。对于性能关键型代码,根本不使用延迟加载。用户必须找到一个位置来初始化上下文
  • 原型:在过程世界中,我们只需返回库存对象的句柄。WinAPI中的GetStockObject函数就是一个例子。对于可变对象,出于性能原因,通常使用写时复制机制
  • Singleton:只需编写顶级函数(在绝对需要全局状态时使用全局变量)

结构模式

  • 适配器立面:在现有接口上构建另一个接口的模式。简单地说,新函数将调用旧函数和其他函数
  • Bridge:对具体实现的回调以设置结构的形式提供
  • Composite:顶级函数用于指定它应该操作的父节点的句柄
  • Decorator:装饰行为以回调的形式提供。或者,为所有可能的装饰提供一个事件处理程序回调,这些装饰接收各种消息并决定是否处理它们(例如WinAPI中的窗口过程)
  • Flyweight:结构和数组中使用的只读二进制数据
  • 代理:与OOP中几乎相同,但没有类

行为模式

  • 责任链:循环遍历的回调数组或链表。规范描述了回调应该如何指示它们处理了导致循环中断的请求
  • 命令:命令是包含doundo回调的结构。这些回调通常需要某种上下文来操作。并且维护一组命令来执行撤消
  • 解释器:编译器/解析器/解释器是使用lex和yacc编写或生成的
  • 迭代器:使用句柄,否则相同。出于C语言的性能原因,我们经常使用数组
  • Mediator:通常通过使用一些消息调度机制、消息循环和事件处理程序来实现
  • Memento:与OOP中相同,但没有类
  • 观察者:与责任链相同,但循环不会中断。atexit就是一个例子
  • 状态:通过二维调度表实现,该表将当前状态和请求的操作映射到一个函数中。(在稀疏的情况下,只使用if。)
  • 策略:这是回调的基本用例
  • 模板方法:通常框架允许用户为某些函数提供自己的回调。库通常提供一种使用自定义内存分配函数的方法,该函数提供自定义mallocfree
  • Visitor:通过使用回调的多维数组来实现,该数组通常在开始时填充NULL(对于默认行为),并填充在每个类型对的主初始化代码中

《设计模式:可重用面向对象软件的元素》一书是一本里程碑式的书,它将设计模式的关注带到了计算机编程、设计和体系结构的实践中。当时占主导地位的编程范式是面向对象的软件开发,这本书显然是针对这种范式,而不是其他范式。尽管你可能会说书中的一些设计模式适用于其他范式,但这并不是本书的重点。因此,受到设计师和程序员欢迎的是那本书中概述的一套设计模式。从那时起,其他作者、博客作者和其他网站都对其他人进行了记录。毫无疑问,有一些设计模式适用于各种网站上描述的过程语言,然而,正如我所说,当编程社区谈到设计模式时,他们大多指的是那本书中概述的模式。我知道这不是一个真正的答案,因为我不知道程序语言的任何文档模式,我相信肯定有一些。我想也许我应该说明这本书的重要性,以及它最初的目标范式

相关内容

  • 没有找到相关文章

最新更新