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

时间:2012-05-08 01:03:00

标签: design-patterns procedural-programming

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

2 个答案:

答案 0 :(得分:26)

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

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

<强>把手

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

示例:

  • 在Windows上,CreateWindow函数返回HWND。哪个是窗口的句柄,可以传递给ShowWindow,DestroyWindow等其他函数。
  • 在Linux上open系统调用。返回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;

在代码中完成以下操作:

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

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

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

OOP设计模式的程序对应

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

创作模式

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

结构模式

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

行为模式

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

答案 1 :(得分:1)

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