【发布时间】:2014-01-07 19:48:52
【问题描述】:
通常,我发现我必须实例化一堆对象,但我发现将此实例化的参数作为人类可读的文本文件提供更容易,我手动编写该文件并将其作为输入输入到程序中。
例如,如果对象是Car,那么文件可能是一堆行,每行包含名称、速度和颜色(三个必需的构造函数参数),并用制表符分隔:
My car 65 Red
Arthur's car 132 Pink
Old junk car 23 Rust brown
这对我来说很容易目视检查、修改或由另一个程序生成。然后程序可以加载文件,获取每一行,解析出相关参数,将它们输入Car(string name, int speed, uint color) 构造函数并创建对象。
注意在输入与构造函数兼容之前必须对输入进行一些工作:必须通过调用int.Parse 将速度从string 转换为int。颜色必须通过查找英文颜色名称来匹配 RGB 值(也许程序会访问 Wikipedia 以找出每种颜色的值,或者在某处查阅名称的预定义映射 -> RGB)。
我的问题是,从 OOP 的角度来看,谁应该做这个解析?构造函数,还是调用构造函数的方法?
第一个选项的优点是简单。调用函数必须只做:
foreach(var row in input_file)
list_of_objects_that_i_am_populating.Add(new Car(row));
并且所有难看的解析都可以很好地包含在构造函数中,反正没有太多其他代码,所以解析代码可以很容易地阅读和修改,而不会被非解析代码分心。
缺点是代码重用已经过时了,因为现在我的对象在臀部连接到输入格式(更糟糕的是,因为输入格式是临时和手动组合的,它是短暂的并且可能无法保证保留相同)。如果我在另一个程序中重用这个对象,我决定稍微改变输入文件的格式很方便,那么两个版本的对象定义现在是不同的。我经常发现自己在构造函数的注释部分定义输入格式,这似乎有点代码异味。
另一个缺点是我失去了进行批处理操作的能力。回想一下前面将颜色名称映射到值的示例问题:如果我使用的 Web 服务需要 1 分钟来处理每个单独的请求,而不管该请求是要求转换一个颜色名称还是一百万个颜色名称。对于一个非常大的输入文件,我会通过为每一行访问一次服务来大大减慢我的应用程序,而不是为所有行提交一个大请求,然后根据回复实例化对象。
处理这种情况的“正确”方法是什么?我是否应该解析输入构造函数并将上述问题视为必须逐案处理的异常问题?我是否应该让我的调用方法进行解析(即使它可能已经被很多复杂的程序逻辑所淹没)?
【问题讨论】:
-
我会使用一个单独的类来解析数据并返回一个
Car对象。通常这是通过工厂模式完成的(有 3 个,选择一个具有足够抽象来满足您的需求)。构造函数用于初始化字段,而不是执行逻辑。