Фабрика объектов на C вместо C

#c #c #design-patterns

#c #c #шаблоны проектирования

Вопрос:

Я конвертирую кучу кода из C в C. Существует ли эквивалентный шаблон в C для фабрики объектов?

Рассмотрим следующий исходный код. На основе параметра int type ( ObjectFactory ) функция () должна возвращать указатель void на структуру типа pedicure . Как я могу создать экземпляр структуры таким образом, чтобы у меня был указатель на нее после возврата функции.

 typedef struct {
    unsigned int a; 
    unsigned int b; 
    unsigned int c; 
} CThings ; 

typedef struct {
    unsigned int d; 
    unsigned int e; 
    unsigned int f; 
} CPlaces ; 

void * ObjectFactory( int type ) {

    switch( type ) {
        case 5 : {          
            return ??? CPlaces ; 
            break; 
        }
        case 35 : {         
            return ??? CThings ; 
            break; 
        }
        default: {
            // unknown type 
            return NULL ; 
        }
    }

    return NULL ; 
}



int _tmain(int argc, _TCHAR* argv[])
{
    void * p = ObjectFactory( 5 ); 

    // Do soemthing with the pointer. 
    CPlaces * places = (CPlaces*) p ; 

    places->d = 5 ; 
    places->e = 6 ; 
    places->f = 7 ; 


    return 0;
}
  

Комментарии:

1. Это, перевод C на C, на первый взгляд кажется особенно глупым упражнением. Не могли бы вы объяснить причины, по которым вы занимаетесь такой явно бессмысленной деятельностью?

2. @AlfP.Steinbach 1: Лучший комментарий, который вы когда-либо писали.

3. @Mooing Duck, ты не можешь этого сделать, как я уже говорил в своих вопросах, это C, а не C , и ключевое слово ‘new’ не существует.

4. Зачем вообще использовать этот термин object , если C является императивным языком программирования

5. @Itsik: объектная ориентация не исключает императивного стиля в языке. C , конечно, не декларативный, хотя и объектно-ориентированный. (хотя вы, конечно, правы; в C нет объектов)

Ответ №1:

Как насчет использования malloc :

 case 5: return malloc(sizeof(struct CPlaces));
  

Нет необходимости в break if, который вы уже возвращаете. Если хотите, вы можете добавить некоторую инициализацию перед возвратом.

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

Ответ №2:

 #include <stdlib.h>

typedef enum enum_ObjectType {
    CPlaces_Object = 5,
    CThings_Object = 35,
} ObjectType;

typedef struct struct_CThings {
    unsigned int a;
    unsigned int b;
    unsigned int c;
} CThings;

typedef struct struct_CPlaces {
    unsigned int d;
    unsigned int e;
    unsigned int f;
} CPlaces ;

void *ObjectFactory(ObjectType type) {
    switch( type ) {
        case CPlaces_Object: {
            return malloc(sizeof(CPlaces));
            break;
        }
        case CThings_Object: {
            return malloc(sizeof(CThings));
            break;
        }
        default: { /* unknown type */
            return NULL;
        }
    }
    return NULL;
}

int main(void) {
    CPlaces *places = ObjectFactory(CPlaces_Object);
    CThings *things = ObjectFactory(CThings_Object);

    things->a = 2;
    things->b = 8;
    things->c = 4;

    places->d = 5;
    places->e = 7;
    places->f = 3;

    return 0;
}
  

Комментарии:

1. К сожалению, это не совсем эквивалентно фабрике объектов C . Я бы ожидал, что мои объекты будут инициализированы чем-то другим, кроме мусора. Я бы предложил использовать параметр varargs, а также иметь функции «конструктора», которые переносят malloc и инициализацию. Эти конструкторы могут быть перегружены, чтобы принимать переменные и вызывать «настоящие» конструкторы после распаковки переменных.

2. Давайте, пожалуйста, не будем возиться с varargs. Если типы действительно связаны, и также разумно создать для них фабрику, тогда мы должны логически ожидать, что сможем построить любой из них с общим набором аргументов. Я имею в виду, что, используя varargs, нам в основном нужно знать, какой конструктор будет передан в любом случае, что, в свою очередь, означает, что мы должны знать, какой тип мы создаем, поэтому мы могли бы также создать его напрямую.

3. @Майкл Прайс, если вы не хотите, чтобы случайный мусор вызывал calloc вместо malloc; D

4. @Angelo’Sphere calloc по-прежнему не инициализирует мои «члены» так, как я хочу, чтобы они были. Если цель состоит в том, чтобы эмулировать объекты C на C, то это необходимо. ООП на C не является невозможным, просто он очень подробный.

5. @MichaelPrice Технически ничто не мешает вам указать функцию для инициализации структуры перед возвращением. Но, как вы сказали, реализация механизма классов на обычном C требует много тяжелой работы.