Fork me on GitHub

基本类型偏执?

Google代码健康

Posted by Kaelzhang on July 13, 2020

Google代码健康:基本类型偏执?

本文源于Google公司的马桶上的健康代码,作者:Marc Eaddy

编程语言会提供在很多上下文下有用的一些基本类型,如:integers, strings, 及maps. 比如:一个string可用于保存从个人名字到网页URL的所有内容。 但是,如果过于依赖基本类型而不是自定义抽象的代码可能很难理解和维护

基本类型偏执是指过度使用基本类型来代表更高级别的概念。 如下代码所示的使用基本类型来表示形状:

vector<pair<int, int>> polygon = ...
pair<pair<int, int>, pair<int, int>> bounding_box = GetBoundingBox(polygon);
int area = (bounding_box.second.first  - bounding_box.first.first) *
           (bounding_box.second.second - bounding_box.first.second);

pair不是正确的抽象级别,因为在一种情况下,其通用名称的first字段和second字段用于表示X和Y,左下角(左上角?)和右上角(右下角? )。 更糟糕的是,基本类型不会封装领域特定代码,如:计算边长和面积。

使用更高级别的抽象替换基本类型可以产生更清晰,封装性更好的代码:

Polygon polygon = ...
int area = polygon.GetBoundingBox().GetArea();

这里还有些其他基本类型偏执的示例:

  • 通过将值合并到自定义的更高层次的抽象中,可以轻松将相关的maps, lists, vectors等组合到单个集合中。
// 反例
map<UserId, string> id_to_name;
map<UserId, int> id_to_age;
// 正例
map<UserId, Person> id_to_person;
  • 具有魔法索引/键的vector或map,例如 索引/键以0、1和2的字符串值分别保存名称,地址和电话号码。 替之以合并这些值成为更高级别的抽象。
// 反例
person_data[kName] = "Foo";
// 正例
person.SetName("Foo");
  • 包含复杂或结构化文本(例如日期)的字符串。 替之以提供自文档访问器(例如GetMonth)并保证正确性的更高级别的抽象(例如Date)。
// 反例
string date = "01-02-03";
// 正例
Date date(Month::Feb, Day(1), Year(2003));
  • 存储时间值的整数或浮点数,例如:秒。 替之以结构化的timestamp或duration类型。
// 反例
int timeout_secs = 5;
// 正例
Duration timeout = Seconds(5);

从简单的int到复杂的红黑树,任何类型都可能太原始而无法完成工作。 如果你看到使用很多基本类型的代码,而这些基本类型可以通过使用更高级别的抽象来进行更清晰或更准确的封装,请对其进行重构或有礼貌地提醒作者使其类化


  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!