2009-05-23 45 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爲二進制文件),都無需更新對象。

我們已經有這樣做的好工作經驗。它非常強大。

相關問題