【问题标题】:Refactoring: Very similar switch cases重构:非常相似的开关案例
【发布时间】:2015-10-19 10:47:09
【问题描述】:

我声明了几个包含不同数据的struct。我还有一个对应于这些结构的enum。我的代码中有几个地方需要访问有关结构的信息,并且我正在通过枚举进行操作。这导致返回此信息的 switch 语句很少。

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

示例伪代码:

#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,但在case 中放置了不同的代码。使用此设置,添加新结构和枚举值会导致代码中的三个位置需要更改。

问题是:有没有办法将其重构为更易于维护的东西?额外的限制是代码是用 C 编写的。

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

【问题讨论】:

  • 这不能在 C 中编译。ABC 是什么?这些名称未声明。 C 确实有“对象”。
  • @Olaf 它只是显示想法的伪代码,而不是整个代码。没有类的情况下,C 怎么有对象?
  • port70.net/~nsz/c/c11/n1570.html#3.15 你也可以在 C 中做 OOP。
  • @Olaf 编辑了问题并添加了工作实现。不过,这个问题更具理论性。

标签: c refactoring


【解决方案1】:

您始终可以使用静态数组并使用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 的评论添加了指定的初始化程序。

【讨论】:

  • 可以通过使用 *designated 初始化器(例如 = { [structA] = "Struct A", .... })使这种方法更加明确。
  • @JensGustedt 是的,这是个好主意,只是需要注意的是,这样的代码不会编译为 C++。
  • 是的,没错,但是在 C++ 中,无论如何,你会以完全不同的方式做这些事情。
【解决方案2】:

你可以把它变成一个函数和一个开关,加上一个额外的参数。像这样

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;

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-17
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    相关资源
    最近更新 更多