2009-05-23 88 views
44

注意:对于长问题抱歉!对象应该将自己写入文件中,还是另一个对象对其执行I/O操作?

我想了解面向对象背后的一些关键领域,我无法以某种方式决定我的特定问题。

比方说,我有一个充满了可爱数据的对象。班bob。

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"); 

有些人是偏袒的选择之一,因为它意味着如果写入文件的代码是改变了,它不需要在每个Save方法中更新;促进代码重用我想。我的问题是从没有访问者的私有数据中获取所有数据。

选项二的情况是,该方法只对该对象所持有的数据起作用,这就是它应该的方式。不受其他物体的干扰。

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

回答

35

一般而言,正确的方法就是您的第1种情况。这种方式对类保持单一责任(不管它是什么),而不将其耦合到特定的持久性机制(磁盘)。

您正在查看一个更普遍问题的特定情况:序列化。一个对象有一些方法可以指出它应该如何序列化,这是好的,也是可以的。毕竟,它是唯一知道反序列化的唯一实体。但是,如果您将该对象保存到磁盘,则会将该对象紧密地耦合到特定的实现。

相反,可以考虑创建一个接口,通用的“writer”可以使用该接口将对象“序列化”到任何作者序列化的对象。这样,您就可以序列化到磁盘,网络,内存,以及您实际需要序列化的任何内容。 :)

+0

那么,情况2可能是正确的,这实际上取决于...在OO设计中没有明确的是或否。例如,你也可以考虑你的对象实现一个IWriter接口的场景。 – 2009-05-23 14:24:34

+1

@divo:总是有例外,那就是设计的本质。这不应该被明确地呼吁。 (这也是为什么我使用“一般”来限定我的声明的原因。) – 2009-05-23 15:22:35

+0

反序列化对象的建议策略是什么?如果传入一个BinaryReader对象并让这个类反序列化它会好吗? – 2009-05-24 03:56:33

24

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

+0

我喜欢。我不认为要使用序列化来处理我的问题。 – 2009-05-23 13:54:05

+4

+1。当您考虑信息隐藏和封装时,可能(一般情况下)序列化Bob的唯一对象是Bob。按照建议,将“保存”概括为写入流以抽象化文件的耦合。 – 2009-05-23 14:20:54

3

我过去更喜欢选项2;然而,由于我已经开始真正尝试了解和模拟我正在开发的领域,我更喜欢选项1.

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

-2

我认为正确的做法是在案例1,但是你的类可以被定义这种方式采取这两种方法的优点:

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); 

    } 
    //... 
} 

这可以很容易地修改,以把写作逻辑和初始化一个基类,所以Bob类更加清洁并且独立于持久性。

9

这是可以使用策略设计模式的示例。你的myBob对象可能有一个将写出它的类的实例。您可能希望编写者实现一个接口或从一个抽象类派生,以便可以轻松更改保存例程。
今天您将保存到xml,但您可能还需要最终将对象保存到数据库。这种模式将允许您轻松更改保存例程。您甚至可以选择更改在运行时保存的方式。

-2

这样做:

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) {...} 
} 

显然,这不是一个完整的解决方案,但你应该得到的总体思路。

3

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

我们已经有这样做的好工作经验。它非常强大。

相关问题