2012-05-08 8 views
10

En mis experiencias, a menudo veo algunos patrones de diseño como patrones de visitantes, patrones de estrategia, ... en lenguajes orientados a objetos como Java ... Pero no he visto muchos patrones en lenguajes de procedimientos como C ... Me pregunto si esos patrones existen en los lenguajes de procedimiento?¿El lenguaje de procedimiento tiene patrones de diseño?

+2

Tenga cuidado al seleccionar las etiquetas para sus preguntas. Las etiquetas son * no * palabras clave. Etiquetar una pregunta con [tag: design] y [tag: patterns] no significa lo mismo que etiquetarlo con [tag: design-patterns]. – Charles

+0

¿Se podría considerar la OOP como un patrón de diseño en un lenguaje de procedimiento? – savagent

+0

@savagent Depende de lo que considere que es un patrón de diseño, generalmente se considera una solución reutilizable para un problema común que se puede aplicar en muchos idiomas diferentes, por lo que no depende de herramientas específicas del idioma, por lo que la mayoría de las el tiempo OOP no es un patrón de diseño. Pero en ANSI-C podría considerarse uno (ver el libro de Schreiner [OOP con ANSI-C] (https://www.cs.rit.edu/~ats/books/ooc.pdf) para ver un buen ejemplo). Consulte esta pregunta para obtener algunas definiciones útiles http://stackoverflow.com/q/4787799/929395 – k3oy

Respuesta

1

El libro "Patrones de diseño: elementos de software reutilizable orientado a objetos" fue un libro histórico que atrajo la atención hacia los patrones de diseño para la práctica de programación, diseño y arquitectura. El paradigma de programación dominante en ese momento era el desarrollo de software orientado a objetos, y el libro estaba claramente dirigido a ese paradigma, y ​​no a otros. Aunque podría argumentar que algunos de los patrones de diseño en el libro se aplicaban a otros paradigmas, no era el objetivo del libro. Entonces, lo que se hizo popular entre los diseñadores y programadores fue el conjunto de patrones de diseño descritos en ese libro. Desde entonces, otros han sido documentados por otros autores, bloggers y otros sitios web. Sin duda, existen patrones de diseño que se aplican a los lenguajes de procedimiento que se han descrito en varios sitios web; sin embargo, como dije, cuando la comunidad de programación habla de patrones de diseño, se refieren principalmente a los patrones descritos en ese libro. Sé que esta no es una respuesta real porque no sé dónde hay patrones documentados para los lenguajes de procedimiento, ciertamente hay algunos, estoy seguro. Pensé que tal vez declararía la importancia de ese libro, y el paradigma al que originalmente estaba dirigido.

17

Los lenguajes de procedimiento de hecho tienen patrones de diseño. Pero dado que el enfoque de procedimiento generalmente se descuida a favor de la POO basada en la clase, no se los reconoce ampliamente.

Desarrollo de software de alto rendimiento en C, y hay varios patrones recurrentes. Así que les daré una idea de los patrones que veo a menudo.

Maneja

Ésta es la forma en la encapsulación se realiza en la programación de procedimiento. La función de construcción no devuelve una estructura o un objeto. Pero un identificador: generalmente es un puntero opaco o simplemente un entero. No puedes hacer absolutamente nada interesante porque es solo un número. Los detalles están completamente ocultos. Pero se puede pasar este identificador para las funciones que tienen que ver con ella:

Ejemplos:

  • En Windows la función devuelve un HWND CreateWindow. Que es un identificador de una ventana, que se puede pasar a otras funciones como ShowWindow, DestroyWindow, etc.
  • En Linux, llama al sistema open. Que devuelve just e int. Que es un manejador de archivo.

Contextos

objetos normalmente son llamados contextos en lenguaje de procedimientos. El contexto es una estructura que contiene el estado de algún sistema, al igual que los miembros de un objeto. En OOP, escriba object.method(parameter). En la programación de procedimientos, escriba function(addressOfContext, parameter). Las funciones internas usan la estructura de contexto directamente, mientras que las funciones públicas solo toman un control y la implementación lo resuelve en la estructura de contexto real.

devoluciones de llamada

o función punteros. El usuario de la función pasa la dirección de su función para agregar un comportamiento personalizado a un sistema. Así es como se realiza el polimorfismo en la programación de procedimientos. Esto permite escribir funciones genéricas.

Un ejemplo notable de esto es la función C qsort. Esto toma la dirección de una matriz de elementos. Toma cuán grande es un elemento y cuántos elementos en el conjunto y una función de comparación que realiza la comparación. Es una implementación completamente genérica y permite clasificar todo tipo de datos.

estructuras de configuración

Cuando una función se puede parametrizar de muchas maneras. Por lo general, se usa una estructura de configuración. Las especificaciones a menudo requieren que estas estructuras llenen cero por defecto, y solo se llenen los miembros relevantes. Si algunos miembros son mutuamente excluyentes, se los coloca en una unión. Un ejemplo típico de dicha estructura de configuración es el WNDCLASS de WinAPI.

datos de tamaño variable

Bueno, esto es más bien un patrón C que en un patrón de diseño general. A veces los objetos pueden contener una carga útil binaria de tamaño arbitrario. Este patrón generalmente ocurre al leer datos de archivos binarios que pueden contener varios tipos de fragmentos de datos. Eso es hecho por una estructura como esta.

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

Y en el código siguiente se hace:

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

memoria Esto asigna eso es más grande que la estructura que permite espacio para una carga útil de longitud variable. Cuyo quinto byte se puede acceder por ej. vs->payload[4].

La ventaja de esto es que el objeto completo se puede liberar en una llamada free. Y se garantiza que tenga un bloque continuo en la memoria. Por lo tanto, utiliza el caché mejor que asignar el búfer correspondiente en otro lugar del montón.

homólogos de procedimiento de patrones de diseño de programación orientada a objetos

patrones de programación orientada a objetos no son llamados en sus nombres en las lenguas de procedimiento. Así que solo puedo adivinar aquí.

patrones Creación

  • fábrica abstracta: Una fábrica abstracta es generalmente un producto único. En ese caso, este patrón no se usa en absoluto y en su lugar se usa la compilación condicional. De lo contrario, las estructuras de configuración proporcionan las funciones de creación.
  • Generador: se utilizan estructuras de instalación.
  • Método de fábrica: las devoluciones de llamadas se utilizan para la creación.
  • Inicialización diferida: en C++ se usan variables locales estáticas para este propósito. En C, puede usar el patrón if (!initialized) { initialize(); initialized = 1; } en lugares que no son críticos para el rendimiento. Para el código de rendimiento crítico, la carga diferida no se utiliza en absoluto. El usuario debe encontrar un lugar para inicializar el contexto.
  • Prototipo: En el mundo de los procedimientos, simplemente devolvemos los identificadores a los objetos de stock. Un ejemplo de esto es la función GetStockObject en WinAPI.Para objetos mutables, un mecanismo de copia sobre escritura se usa a menudo por motivos de rendimiento.
  • Singleton: simplemente escriba funciones de nivel superior (y utilice variables globales cuando necesite absolutamente el estado global).

patrones estructurales

  • adaptador y Fachada: Un modelo para la construcción de otra interfaz en una ya existente. Simplemente funciones nuevas llamarán a las antiguas y otras.
  • Bridge: Las devoluciones de llamadas a las implementaciones concretas se proporcionan en forma de estructura de configuración.
  • compuesto: las funciones de nivel superior se utilizan especificando un identificador para el nodo principal en el que debería funcionar.
  • Decorador: El comportamiento de decoración se proporciona en forma de devoluciones de llamada. O bien, se proporciona una devolución de llamada del manejador de eventos para todas las decoraciones posibles que recibe varios mensajes y decide manejarlos o no (por ejemplo, el procedimiento de ventana en WinAPI).
  • Flyweight: datos binarios de solo lectura utilizados empaquetados en estructuras y matrices.
  • Proxy: prácticamente lo mismo que en OOP, pero sin clases.

patrones de comportamiento

  • cadena de responsabilidad: una matriz o lista enlazada de devoluciones de llamada atravesados ​​por un bucle. La especificación describe cómo deben las devoluciones de llamadas indicar que manejaron la solicitud causando la ruptura del ciclo.
  • Comando: Los comandos son estructuras que contienen una devolución de llamada do y undo. Estas devoluciones de llamada suelen tener algún tipo de contexto para operar. Y una serie de comandos se mantienen para realizar el deshacer.
  • Intérprete: Un compilador/analizador/intérprete se escribe o genera utilizando lex y yacc.
  • Iterador: Se usan los mangos, de lo contrario, lo mismo. Por motivos de rendimiento en C, a menudo nos limitamos a las matrices.
  • Mediator: Usualmente se realiza mediante el uso de algún mecanismo de envío de mensajes y message loops y controladores de eventos.
  • Memento: Igual que en OOP, pero sin clases.
  • Observer: Igual que la cadena de responsabilidad, pero el lazo no se romperá. Un ejemplo es el atexit.
  • Estado: Realizado por 2 tablas dimensionales de envío que mapea el estado actual y la operación solicitada en una función. (En casos dispersos, simplemente se usan ifs).)
  • Estrategia: Este es el caso de uso básico de devoluciones de llamada.
  • Método de plantilla: Normalmente, los marcos permiten al usuario proporcionar sus propias devoluciones de llamada para algunas funciones. Las bibliotecas a menudo proporcionan una forma de utilizar la función de asignación de memoria personalizada proporcionando un malloc personalizado y free.
  • Visitante: se realiza mediante el uso de matrices multidimensionales de devoluciones de llamadas, que normalmente es NULL completado al inicio (para el comportamiento predeterminado), y se rellena en el código de inicialización principal para cada par de tipos.