7

代码健康(3):不要痴迷于原始类型?

 2 years ago
source link: https://www.continuousdelivery20.com/blog/ch-not-obsessed-with-primitives/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

乔梁 | 2021-03-03

不要痴迷于原始类型

编程语言提供基本类型,如 int ,string 和 map ,这些类型在许多场景下都被用到,例如,利用 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 在这里并不是一个正确的抽象层次,因为它的一般命名 firstsecond 两个参数被用于表示 XY,其中一处被用做标识 lower-left (或者, upper-left?) 而另外一处用作 upper-right (或, lower-right?) 。更糟糕的是,基本类型并没有对领域专属的代码进行封装,例如边框(bounding box)和面积(area)。

自定义并使用更高级别的抽象类型,写的代码可能更清晰,而且封装性更好:

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分别代表name, address, and phone #,应该将其放入到更高一级的抽象中。

    person_data[kName] = "Foo";person.SetName("Foo");
  • 用一个字符串表示复杂或结构化的文本(例如一个日期)。更好的做法是使用更高层的抽象(如 Date 类型) ,它还提供自我说明的访问函数(例如 GetMonth ) ,并且还保证正确性。

    string date = "01-02-03";Date date(Month::Feb, Day(1), Year(2003));
  • 用一个整型或浮点数表过一个时间值,例如多少秒。更好的做法是使用结构化的时间戳( timestamp )或时间段类型( duration )。

    int timeout_secs = 5;Duration timeout = Seconds(5);

对于某个任务来说,任何类型都可能显得过于原始,从最原始的 int ,到复杂的红黑树。

如果你看到代码使用了很多的基础类型,那么,使用更高级别的抽象更能够表达清楚,封装性也会更好。你应该把它重构了,或者礼貌地提醒作者要 保持优雅


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK