Реализация фабричного шаблона с использованием ANSI C

Может ли кто-нибудь указать мне ссылку на то, как реализовать фабричный шаблон с использованием ANSI C? Если будет охвачено больше шаблонов, это будет просто бонусом. Сделать это на C ++ для меня тривиально, но поскольку C не имеет классов и полиморфизма, я не совсем уверен, как это сделать. Я думал о том, чтобы иметь «базовую» структуру со всеми распространенными типами данных, а затем использовать указатели void и определять все общие части структур в том же порядке, что и в базовой структуре вверху? Или нет гарантии, что они так же попадают в память?


person inquam    schedule 08.07.2010    source источник
comment
Вы можете сделать полиморфизм на C, но это некрасиво. См. Следующие вопросы: stackoverflow.com/questions/524033/ stackoverflow.com/questions/351733/ stackoverflow.com/questions/415452/object-orientation-in-c   -  person Adam Rosenfield    schedule 08.07.2010


Ответы (4)


В C есть указатели на функции и структуры. Таким образом, вы можете реализовать классы на C.

что-то вроде этого должно дать вам ключ к разгадке.

void class1_foo() {}
void class2_foo() {}

struct polyclass
{
    void (*foo)();
};

polyclass make_class1() { polyclass result; result.foo = class1_foo; return result; }
person yatagarasu    schedule 08.07.2010

Заводской шаблон также может быть реализован на C, предположим, что следующие операции определяются вашим интерфейсом:

typedef int (*operations_1) (void *data);
typedef int (*operations_2) (void *data);

typedef struct impl_ops_t
{
    operations_1 op1;
    operations_2 op2;
} impl_ops_t;

Итак, чтобы иметь возможность получить экземпляр реализации, реализующий такой интерфейс, вы должны определить структуру как с данными, так и с операциями, затем вы можете определить операцию создания, которая вернет вам эту структуру и, возможно, также операции уничтожения:

typedef struct ctx_t
{
    void       *data;
    impl_ops_t *operations;
} ctx_t;

typedef ctx_t   (*create_handle)   (void);
typedef void    (*destroy_handle)  (ctx_t **ptr);

typedef struct factory_ops
{
    create_handle  create;
    destroy_handle destroy;
} factory_ops;

Вы также должны определить функцию, которая предоставляет вам фабричные методы, возможно, у вас должен быть способ получить правильную реализацию в зависимости от ваших потребностей (возможно, это не простой параметр, как в примере ниже):

typedef enum IMPL_TYPE
{
    IMPL_TYPE_1,
    IMPL_TYPE_2
} IMPL_TYPE;
factory_ops* get_factory(int impl_type);

Таким образом, он будет использоваться как:

main (...)
{
    factory_ops fact = get_factory(IMPL_TYPE_2);

    // First thing will be calling the factory method of the selected implementation
    // to get the context structure that carry both data ptr and functions pointer
    ctx_t *c = fact->create();

    // So now you can call the op1 function
    int a = c->operations->op1(c->data);
    // Doing something with returned value if you like..
    int b = c->operations->op2(c->data);
    // Doing something with returned value if you like..

    fact->destroy(&c);
    return 0;
}
person Giordano    schedule 26.03.2013
comment
Поздравляю! Это красивый и изящный пример! Спасибо! - person kazbeel; 08.09.2014
comment
Я новичок в заводском шаблоне и пишу только C. Этот пример мне очень противоречит. Почему бы просто не позвонить operations_1 и operations_2 напрямую? Есть ли польза от использования указателя на указатель на функцию? - person Andy Lin; 10.01.2021
comment
Чтобы понять причины, я бы порекомендовал вам попробовать реализовать такой фабричный паттерн без использования указателя на функцию. - person Giordano; 18.01.2021

Здесь, внизу страницы, находится серия статей о шаблонах в C

person pcent    schedule 08.07.2010

Шаблон Factory - это объектно-ориентированный шаблон проектирования.

C не является объектно-ориентированным языком.

Поэтому я бы спросил, какова ваша цель для Factory на C.

person Justin Niessner    schedule 08.07.2010
comment
Модуль, который я собираюсь построить, действительно подходит для заводского дизайна. Но компания придерживается строгой политики использования только ansi C. - person inquam; 08.07.2010
comment
@inquam - Понятно, но не могли бы вы дать нам пример того, для чего вам нужна фабрика (поскольку обычно Factory используется для создания экземпляра интерфейса, поддерживаемого различными реализациями классов)? - person Justin Niessner; 08.07.2010
comment
Я знаю, и это то, что я хочу ... Но мне приходится бороться с ограничениями C. Допустим, вы создали систему, которая будет сканировать файлы на вирусы и сообщать о результатах. Есть много разных способов, и в будущем может появиться еще больше способов обнаружения различных вирусов. Но отчетная часть у всех одинакова. Если бы у меня был способ создать базу со структурой данных для хранения данных отчета и т. Д. Аналогичным образом, все разные сканеры могли бы выполнять одни и те же функции отчетов. Но реальная работа, которую они должны сканировать, может быть разной. - person inquam; 08.07.2010
comment
Я не согласен. Объектная ориентация - это парадигма, парадигма, которая может быть реализована с помощью C. Я не говорю, что это хорошая идея. - person manneorama; 08.07.2010
comment
@manneorama - объектно-ориентированное программирование определяется как язык, поддерживающий три основных концепции: наследование, полиморфизм и инкапсуляция. Без наследования и полиморфизма ... C не подходит. - person Justin Niessner; 08.07.2010
comment
@Justin, Все, чего можно добиться с помощью C. Взгляните на этот вопрос например; stackoverflow.com/questions/415452/object-orientation- in-c /. Я не утверждаю, что C предназначен для объектно-ориентированного использования, и я не говорю, что его следует использовать таким образом вместо, возможно, более функционального языка. Я говорю, что если кто-то по какой-то причине захочет это сделать, это возможно и может быть сделано. При значительных усилиях и очень небольшом выигрыше =) - person manneorama; 08.07.2010