一个对象是否应该把自己写到一个文件中,或者另一个对象是否应该用它来执行I / O?

注意:对于长问题抱歉!

我试图理解面向对象背后的一些关键领域,我不能以某种方式来决定我的特定问题。

假设我有一个充满可爱数据的对象。 classbob。

Bob myBob = new Bob("This string is data"); 

假设我想将myBob的内容保存到一个xml文件(bob.xml)

我应该有一个对象作用于鲍勃写出的内容,或者我应该有myBob做这个?

案例1:对目标行事

 Writer myWriter = new Writer(myBob, "C:\\bob.xml"); 

情况2:保存方法

 myBob.Save("C:\\bob.xml"); 

有些人正在select一个选项,因为这意味着如果写入文件的代码改变了,不需要在每个Save方法中更新; 促进代码重用我想。 我的问题是获取所有数据的对象可能有私人数据没有访问者。

scheme2的情况是该方法仅对对象所持有的数据起作用,这就是应该的方式。 没有其他物体的干扰。

或者是我的问题的“案件依赖”问题之一的答案? 如果是这样,你怎么知道一种方法比另一种方法更受欢迎?

一般而言,正确的方法就是你的情况1.这个方法对类保持一个单独的责任(不pipe它是做什么的),而不把它连接到一个特定的持久机制(一个磁盘)。

你正在看一个更普遍的问题的特定情况:序列化。 一个对象有一些方法可以指出它应该如何被序列化,这是好的,也是可以的。毕竟,它是唯一知道反序列化的唯一实体。 但是如果你把对象保存到磁盘上,你已经把这个对象紧紧地绑定到一个特定的实现上。

相反,可以考虑创build一个接口,通用的“writer”可以用来将对象序列化到序列化的任何对象上。 这样,您就可以序列化到磁盘,networking,内存,以及您实际需要序列化的任何内容。 🙂

我会让Bob知道如何序列化自己,因为它有私人数据。 另一个对象(比如你的Writer )会把它放在磁盘上。 鲍勃知道如何处理其数据最好,但不必关心如何或在哪里存储。 您的作家知道如何最好地保存数据,但不需要关心数据是如何创build的。

这是可以使用策略devise模式的一个例子。 你的myBob对象可以有一个类的实例将它写出来。 您可能希望作者实现一个接口或从一个抽象类派生,以便保存例程可以很容易地更改。
今天你保存到XML,但你可能需要最终坚持对象到数据库以及。 这种模式将允许您轻松更改保存例程。 您甚至可以select更改在运行时保存的方式。

我曾经更喜欢选项2; 然而,正如我开始真正试图理解和模拟我正在工作的领域,我更喜欢选项1。

想象一下,如果你的模型车辆。 为什么汽车会知道如何坚持下去? 它可能知道如何移动,如何开始以及如何停止,但在车辆上下文中保存的是什么。

另一种方法是使用访问者模式。 让你的对象包含一个Accept方法,通过你想要处理/序列化的成员,并有一个访问者是你的序列化。 无论何时您更新或更改您的序列化(纯文本到xml二进制到任何),您不需要更新对象。

我们已经有了很好的工作经验。 这是相当强大的。

我认为正确的做法是案例1,但是您的class级可以这样定义,以利用这两种方法:

 class Bob { IWriter _myWriter = null; public Bob(){ // This instance could be injected or you may use a factory // Note the initialization logic is here and not in Save method _myWriter = new Writer("c://bob.xml") } //... public void Save(){ _myWriter.Write(this); } // Or... public void Save(string where){ _myWriter.Write(this, where); } //... } 

这可以很容易地修改,把写入逻辑和初始化在一个基类,所以鲍勃类更干净,独立于持久性。

做这个:

 public interface Writable { public void Save(Writer w); } public interface Writer { public void WriteTag(String tag, String cdata); } public class Bob : Writable { private String ssn = "123-23-1234"; public void Save(Writer w) { w.WriteTag("ssn", ssn); } } public class XmlWriter : Writer { public XmlWriter(Sting filename) {...} public void WriteTag(String tag, Sting cdata) {...} } 

显然这不是一个完整的解决scheme,但你应该得到一般的想法。