程序语言是否有设计模式?

16 procedural-programming design-patterns

根据我的经验,我经常会看到一些设计模式,比如访问者模式,策略模式......,像Java这样的面向对象语言......但我还没有看到像C这样的过程语言中有太多的模式...我想知道那些程序语言中存在哪些模式?

Cal*_*ius 30

程序语言确实有设计模式.但由于程序方法通常被忽略而偏向于基于阶级的OOP,因此它们并未得到广泛认可.

我用C开发高性能软件,并且有几种重复出现的模式.所以我会提供一些见解我经常看到的模式.

手柄

这就是在过程编程中完成封装的方式.构造函数不返回结构或对象.但是一个句柄:它通常是一个不透明的指针或只是一个整数.你不能做任何有趣的事情,因为它只是一个数字.细节完全隐藏.但是您可以将此句柄传递给处理它的函数:

例子:

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

上下文

对象通常在过程语言中称为上下文.Context是一个包含某个系统状态的结构,就像对象的成员一样.在你写的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;
Run Code Online (Sandbox Code Playgroud)

在代码中完成以下操作:

VariableSized *vs = malloc(sizeof(VariableSized) + extraLength);
Run Code Online (Sandbox Code Playgroud)

这会分配比结构更大的内存,从而为可变长度的有效负载提供空间.然后可以通过例如访问谁的第5个字节.vs->payload[4].

这样做的好处是整个对象可以在一次free调用中释放.并且它保证它在内存中有一个连续的块.因此,它比在堆中的其他位置分配相应的缓冲区更好地利用缓存.

OOP设计模式的程序对应物

OOP模式在程序语言中的名称永远不会被调用.所以我只能猜到这里.

创作模式

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

结构模式

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

行为模式

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

  • 很棒的答案。真正说明了 OOP 并不是最终的解决方案,而且还有其他方式来思考同一问题。 (2认同)

Sun*_*ng2 2

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