使用Integer vs String获取"类型"值(数据库和类设计)

Win*_*ute 11 enums database-design class-design value-type

我一直在开发一些手机游戏,其中那些游戏从服务器数据库中获取数据.

我习惯将"type"值存储为整数标识符,并在客户端中使用枚举来标识来自服务器的数据.

举个例子:在数据库表上:

怪物表:MonsterId(int),名称(字符串),MonsterType(int)

在客户端代码上:

typedef enum {
    MonsterTypeGround = 1,
    MonsterTypeAquatic = 2,
    MonsterTypeAmphibious = 3,
    MonsterTypeAerial = 4
}MonsterType;
Run Code Online (Sandbox Code Playgroud)

请注意,上面的代码是Objective-C,我可以在其中指定整数值.但我也在使用C#和C++.

但是,我们的数据库人说,枚举是一个编译技巧,没有枚举数据类型.他认为整数类型标识符使得人们(其他开发人员)很难理解值的含义,并且他们不可能在不查看客户端代码的情况下知道等价物并且枚举不好因为你需要确保枚举与服务器端ID同步,并且最好使用字符串.

我的问题是:在这个问题上是否有客观正确的答案?

除了在客户端代码上使用枚举之外还有其他选择,但仍然会使用整数作为服务器数据库吗?

All*_*eve 12

答案很长

你的数据库人显然是错的.当然,如果像ENUM数据类型那样.您在示例中提供了一个.MySQL知道它.许多编程语言都有类似ENUM的东西.

但他也是对的,因为ENUM经常(总是?)由编译器优化.如果有四个选项可以完美地由1到4表示,但我们碰巧发现可识别的字符串更容易在代码中读取.但编译器没有这样的问题,实际上并不关心这个数字.空中怪物是类型4,飞行意大利面怪物是类型4.与比较字符串相比,CPU比较字节更容易按几个数量级的顺序.

此外,他是正确的,在C代码中使用ENUM或任何代码可能是一个问题:

  1. 如果更改定义(尤其是顺序),则需要重新编译程序和所有链接的程序(如果它是库).那是一种痛苦.
  2. 如果您需要与不同的语言交互,那也可能是一种痛苦.您需要同步多个定义.
  3. 管理ENUM很麻烦,尤其是删除类型.

你可以通过一个将字符串转换为枚举的函数或其他方法来解决这个问题.

但也有好处:

  1. 如果您更改怪物类型的名称,任何空中怪物都可以保留类型4,即使您将它们重命名为飞行怪物.数据库中的数据一致性是保证的,因为它是一个字符串.如果你使用字符串,就没有无痛的转换方式.好吧,查找和替换将在代码中执行,但不在数据库中执行.
  2. 这是一种有效的格式.它会节省10个字节.我的经验是,这很少重要,除非你有数千万条目.

TL; DR

没有客观的答案.

如果您发现程序员最容易,那么字符串可能是更好的选择.如果您发现编译器优化最重要,那么枚举是更好的选择.

我的观点是编译器优化很少很重要,但程序员时间很少.除了在某些数据库中,我自己主要使用字符串.

所以是的,你的家伙有一个观点.


rad*_*bob 5

好吧,这里是..潜在的downVote饲料,但枚举是我最喜欢的东西之一..

看法

专注于最适合您的设计和代码的内容。不使用枚举是因为数据库没有那种“数据类型”?好的。那么出于同样的原因,我们不要制作任何自定义类。那是胡说八道。

枚举善良

(注意:我用 C# 编码)

  1. 允许您根据问题域声明事物。字符串是字符串,但 MonsterType 枚举是 Monster(类型)。
  2. 枚举本质上是强类型的。使用未定义的枚举值是编译错误。OTOH,字符串拼写错误是另一个调试会话。
  3. 我特别喜欢它的switch声明。Beats theHellOutta 整数:switch(MonsterType)
  4. 枚举可以详尽地定义所有有效值
  5. 倾向于文档-y
  6. 代码质量增强器 - 确保您必须重新编译以添加新成员,但这是经过深思熟虑的,并且缺少相关的代码更改将爆炸(一件好事)与未在某处处理的新字符串值相比,它表现为难以捉摸逻辑/处理错误,需要您进行调试会话。
  7. 默认为零,不为空。有趣的是,空概念可以把事情搞砸。在它所属的数据库中保持“null”。
  8. 专业编码提示:始终明确定义默认成员。回复:MonsterType.Unknown = 0。您的回报将是更容易编写的代码,更少错误且更易于阅读。您的维护程序员会感谢您。

字符串不良

  1. 默认值为空。这是一场围绕空值和“空字符串”的持续战斗。我经常看到像这样的愚蠢的、错误缠身的代码:if(string.IsNullorEmpty(myString.Trim()) ...- 如果 myString 为空,你的程序就会因运行时异常而崩溃。枚举不能发生。
  2. 字符串比较区分大小写
  3. 容易出现拼写错误
  4. “字符串”类型是通用的,绝不会帮助您根据域表达您的问题
  5. myString = null从数据库中获取的设置不是带值的变量,它甚至不是对象,但我们尝试像对待它一样对待它!

整数混淆

if (MonsterType == 3)... 这是什么意思?纳夫说。

这是一个实践练习。在您的 IDE 中,单击“3”并让它“查找定义”。如果您的 IDE 会说话,它会说“为什么不定义问题域中的事物,而不是指望我猜“3”是什么意思?

哦,我知道。我会在某处声明一堆常量......在某处。我的天啊。让我们假设我们正在使用枚举!它比使用一有凝聚力的类型安全值更有趣!

null让我发疯

C# 有一个String.Empty静态属性是有原因的。它不会劫持有效值(例如空格)或 null 来表示实例化的字符串对象,该对象的值明确不是任何(有效)字符串。这与空值不同。

从字面上看,null 没有任何意义。意思是“走开,没人在家”。例如,编码人员通常希望它表示“未知的怪物类型”,但为了大声喊叫,明确定义此类概念(请参阅上面的枚举专业提示)。恕我直言,像这样使用 null 意味着您的设计缺少某些东西。

null 是代码僵尸。它在四处走动,但什么也没有,死了,无论如何。如果你不小心,它会咬你!

您将体验到决定将“空”字符串存储为空格字符或空字符的永无止境的乐趣;

并且空格实际上是有效的字符串域值,而不是“无值”值;

并且 null 和“空字符串”确实没有任何意义,并且在您需要它们的“自然”功能时试图使它们如此会导致问题;

以及从 string.empty 到 null 到 space 的不断大惊小怪的代码转换,反之亦然,以适应手头的任务。随着时间的推移,您的代码将在这方面变得不一致。

现在听我说,以后相信我。