重构:非常相似的开关案例

时间:2015-10-19 10:47:10

标签: c refactoring

我声明了几个包含不同数据的struct。我还有一个与这些结构相对应的enum。我的代码中有几个地方需要访问有关结构的信息,我通过枚举来完成。这导致很少switch个语句返回此信息。

我已将这些switch语句包含在自己的函数中,以便尽可能重用。这导致三个功能看起来非常相似。

psuedo-code示例:

#include <stdio.h>

typedef struct
{
    int varA;
char varB;
} A;

typedef struct
{
     int varA;
     int varB;
     int varC;
} B;

typedef struct
{
     int varA;
     short varB;
} C;

typedef enum { structA, structB, structC } STRUCT_ENUM;

int returnSize(STRUCT_ENUM structType)
{
     int retVal = 0;
     switch(structType)
     {
          case structA:
               retVal = sizeof(A);
               break;
          case structB:
               retVal = sizeof(B);
               break;
          case structC:
               retVal = sizeof(C);
               break;
          default:
               break;
      }

      return retVal;
}

void printStructName(STRUCT_ENUM structType)
{
     switch(structType)
     {
          case structA:
               printf("Struct: A\r\n");
               break;
          case structB:
               printf("Struct: B\r\n");
               break;
          case structC:
               printf("Struct: C\r\n");
               break;
          default:
               break;
      }
}

void createDataString(STRUCT_ENUM structType, char* output, unsigned char* input)
{
     switch(structType)
     {
          case structA:
          {
               A a = *(A*)input;
               sprintf(output, "data: %d, %d", a.varA, a.varB);
               break;
          }
          case structB:
          {
               B b = *(B*)input;
               sprintf(output, "data: %d, %d, %d", b.varA, b.varB, b.varC);
               break;
          }
          case structC:
          {
               C c = *(C*)input;
               sprintf(output, "data: %d, %d", c.varA, c.varB);
               break;
          }
          default:
               break;
      }
}

int main(void) {
    char foobar[50];

    printf("Return size: %d\r\n", returnSize(structA));
    printStructName(structB);

    C c = { 10, 20 };
    createDataString(structC, foobar, (unsigned char*) &c);
    printf("Data string: %s\r\n", foobar);

    return 0;
}

这些自由函数基本上包含相同的switch,并且在案例中放置了不同的代码。通过此设置,添加新的struct和enum值会导致代码中需要更改的三个位置。

问题是:有没有办法将其重构为更易于维护的东西?附加约束是代码是用C语言编写的。

编辑:在线示例:http://ideone.com/xhXmXu

2 个答案:

答案 0 :(得分:3)

您始终可以使用静态数组并使用STRUCT_ENUM作为索引。鉴于你的功能的性质,我不知道你是否会认为它更易于维护,但它是我通常喜欢的替代品,名称和尺寸的例子:

typedef enum { structA, structB, structC, STRUCT_ENUM_MAX } STRUCT_ENUM;
char *struct_name[STRUCT_ENUM_MAX] = {[structA] = "Struct A", [structB] = "Struct B", [structC] = "Struct C"};
size_t struct_size[STRUCT_ENUM_MAX] = {[structA] = sizeof(A), [structB] = sizeof(B), [structC] = sizeof(C)};

对于打印内容,你可以保留一个类似的函数数组,接收一个void *来打印这个参数的值。

修改 根据Jen Gustedt的评论添加了指定的初始化程序。

答案 1 :(得分:1)

您可以使用附加参数将其转换为单个功能和单个开关。像这样

int enumInfo(STRUCT_ENUM structType, int type) // 1 = returnSize 2 = printStructName
{
     int retVal = 0;
     switch(structType)
     {
          case structA:
               If ( type == 1 ) { retVal = sizeof(A); }
               else { printf("Struct: A"); }
               break;
          case structB:
               If ( type == 1 ) { retVal = sizeof(B); }
               else { printf("Struct: B"); }
               break;
          case structC:
               If ( type == 1 ) { retVal = sizeof(C); }
               else { printf("Struct: C"); }
               break;
          default:
               break;
      }

  return retVal;

}