Answers:
如果您使用的语言支持该功能,那么我将提供一个采用Stream的Save方法。这样,用户可以在他或她想要的任何地方保存数据。
与仅保存到文件相比,写入要花费20秒的时间,但是程序员容易理解,并且在调用站点非常清楚实际发生了什么。
否则,您描述它的方式(一个读取输入并输出到另一个文件的对象)似乎很奇怪。构造在构造过程中执行所有操作的对象的目的是什么?
你会这样称呼吗?
var stuff = DoStuff();
new SaveFileWeirdClass(stuff);
return;
对于SaveFileWeirdClass的任何合理实现,我希望仅创建它就不会产生副作用。读取文件-很好。创建文件?没有。
在我看来,这样更清晰:
var stuff = new StuffReader(); //Better name needed...
string filePath = this.whatever;
using(Stream stream = new FileStream(filePath))
stuff.Save(stream);
如果您打算在课堂上这样做,请在初始化期间创建它。延迟该步骤有两个不好的事情:首先,它为调用者添加了一个额外的明确步骤,该调用者不会首先创建对象,除非他们打算使用该对象来产生输出。其次,它至少增加了两点,类中的代码必须决定文件是否打开并处理该条件:一次是写输出,一次是销毁期间的关闭。前者意味着您必须在每次写操作时都要进行检查,如果您要进行很多操作,这可能会很浪费。
就我个人而言,我什么都不做,而是选择让调用者将预打开的文件句柄传递给构造函数。在类内创建文件将使调用者无法选择设置权限或(如果写入设备时)进行设备特定的初始化等操作。如果您希望使用可以FooConverter
在文件上运行的类的版本,并且可以正常执行创建工作,请将其包装在中FooFileConverter
。
明确地。
您要确保您不要依赖于可能在将来的版本中或在不常见的体系结构上中断的聪明的副作用规则。当然,您应该具有一个默认文件,用户可以选择覆盖该文件。
除了显式方法的其他参数外:如果您在构造函数中进行工作,那么您将迫使类的每个用户仅出于创建对象的目的进行异常处理。这会导致很多样板代码。
有关此方面的讨论,请参见/programming/6086334/is-it-good-practice-to-make-the-constructor-throw-an-exception。