对象是应该将自己写入文件,还是应该使用其他对象来执行I / O?

时间:2009-05-23 13:47:59

标签: c# design-patterns oop io

注意:很抱歉这个问题很长!

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

假设我有一个充满可爱数据的对象。班级鲍勃。

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

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

我是否应该让一个对象在bob上写出内容,或者我应该让myBob这样做吗?

案例1:对象行为

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

案例2:保存方法

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

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

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

或者是我的问题的答案之一是“案例依赖”问题?如果是这样,你怎么知道何时一种方法优先于另一种?

7 个答案:

答案 0 :(得分:36)

一般来说,正确的方法是你的案例1.这样就保持了对类(无论它做什么)的单一责任,而没有将它耦合到特定的持久性机制(磁盘)。

您正在查看更广泛问题的特定情况:序列化。一个对象有一些方法来指示它应该如何被序列化是好的和好的 - 毕竟它是唯一知道反序列化它的必要实体。但是,如果您将对象保存到磁盘,则会将该对象与特定实现紧密耦合。

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

答案 1 :(得分:25)

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

答案 2 :(得分:9)

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

答案 3 :(得分:3)

我以前更喜欢选项2;但是,由于我已经开始真正尝试理解和建模我正在研究的域名,我更喜欢选项1。

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

答案 4 :(得分:3)

另一种方法是使用访客模式。让您的对象包含一个Accept方法,该方法遍历您要处理/序列化的成员,并让访问者成为您的序列化程序。每当您更新或更改序列化(纯文本到xml到二进制到任何)时,您不需要更新对象。

我们在工作中有很好的经验。它非常强大。

答案 5 :(得分:-3)

这样做:

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

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

答案 6 :(得分:-4)

我认为正确的方法是案例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类就更清晰,独立于持久性。