2009-07-01 131 views
5

我有一個支持某些設備的多種類型和版本的應用程序。它可以連接到這些設備並檢索各種信息。創建可擴展屬性類(OOP)

根據設備的類型,我有(除其他外)可以包含各種屬性的類。一些屬性對於所有設備是通用的,一些屬性對於特定設備是唯一的。

該數據被序列化爲xml。

在未來的這些設備版本中實現一個支持未來屬性的類的首選方法是什麼?以及向後兼容以前的應用程序版本?

我能想到的幾種方法,但我覺得他們都不大:

  • 使用名稱 - 值對的集合:
    • 利弊:良好的向後兼容性(XML和我的應用程序的先前版本)和可擴展性,
    • 缺點:沒有類型安全性,沒有智能感知,需要實現自定義xml序列化(以處理不同的value個對象)
  • 爲每個新的設備創建派生屬性類:
    • 優點:類型安全
    • 缺點:必須使用XmlInclude或自定義序列反序列化派生類,沒有向後與以前的xml模式的兼容性(儘管通過實現自定義序列化我可能跳過未知屬性?),需要轉換以訪問派生類中的屬性。
  • 另一種方法呢?

順便說一句,我使用的是C#。

+0

是XML必需?你的兩個缺點都說XML必須被處理。這感覺就像你不想使用XML ... – tuergeist 2009-07-01 09:04:07

+0

是的,這是客戶知道的一個流行語要求。 :) – Groo 2009-07-01 09:11:24

+0

我會選擇「爲每個新設備創建派生的屬性類」... – tuergeist 2009-07-01 09:17:18

回答

2

如何處理類似於PropertyBag的東西?

+0

那麼,這基本上是一個名稱 - 值對的集合,我不在乎內部實現如此之多(列表,字典,隨你)。但它也有同樣的缺點。 – Groo 2009-07-01 09:15:01

+1

這是我們在最後使用的,謝謝! – Groo 2009-10-05 06:50:51

0

我認爲創建派生屬性是最好的選擇。

您可以使用xml模式來設計您的新類。然後用xsd.exe生成類代碼。

使用.net並不難開發一個泛型類,它可以序列化和反序列化xml中的所有類型。

public static String toXmlString<T>(T value) 
{ 
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 
    StringWriter stringWriter = new StringWriter(); 
    try { xmlSerializer.Serialize(stringWriter, value); } 
    catch (Exception e) 
    { 
     throw(e); 
    } 
    finally { stringWriter.Dispose(); } 
    String xml = stringWriter.ToString(); 
    stringWriter.Dispose(); 
    return xml; 
} 

public static T fromXmlFile<T>(string fileName, Encoding encoding) 
{ 
    Stream stream; 
    try { stream = File.OpenRead(fileName); } 
    catch (Exception e) 
    { 

     e.Data.Add("File Name", fileName); 
     e.Data.Add("Type", typeof(T).ToString()); 
     throw(e); 
    } 

    BufferedStream bufferedStream = new BufferedStream(stream); 
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 

    TextReader textReader; 
    if (encoding == null) 
     textReader = new StreamReader(bufferedStream); 
    else 
     textReader = new StreamReader(bufferedStream, encoding); 

    T value; 
    try { value = (T)xmlSerializer.Deserialize(textReader); } 
    catch (Exception e) 
    { 
     e.Data.Add("File Name", fileName); 
     e.Data.Add("Type", typeof(T).ToString()); 
     throw(e); 
    } 
    finally 
    { 
     textReader.Dispose(); 
     bufferedStream.Dispose(); 
    } 
    return value; 
} 
0

從編程上講,這聽起來像是它可能是Decorator Pattern的工作。從本質上講,你有一個超類,它爲所有這些類型的設備定義了一個通用接口。然後你有裝飾類,其中有設備可能具有的其他屬性。而且,在創建這些設備時,您可以動態添加這些裝飾以定義設備的新屬性。圖形:

alt text

你可以看一下維基百科頁面更詳細的說明。之後,這只是一個序列化的問題,可以告訴程序加載哪些裝飾器。

1

如果您不侷限於與外部模式的互操作性,那麼您應該使用Runtime Serialization和SoapFormatter。運行時序列化模式允許派生類指定哪些屬性需要序列化,以及在反序列化時如何處理它們。

XML序列化程序需要XmlInclude,因爲它實際上需要定義要使用的模式。

1

我喜歡這種事情的名稱/值集。

您可以處理很多缺點 - 考慮一個基類,它充當通用名稱/值集合,其中沒有操作方法用於驗證傳入的名稱/值對。對於已知的名稱集(即鍵),可以創建實現驗證方法的派生類。

例如,打印機可能有一個只能是「真」或「假」的已知鍵「PrintsColor」。如果有人試圖加載PrintsColor =「CMYK」,你的Printer類會拋出異常。根據你在做什麼,你可以通過幾種不同的方法來使驗證更方便 - 基類中的實用方法(例如checkForValidBoolean())或接受名稱/類型的基類信息在它的構造函數中用於派生類中的更乾淨的代碼,也許是一種主要是自動化的XML序列化。

對於intellisense - 您的派生類可能具有基本訪問器,這些訪問器是通過密鑰查找來實現的。智能感知將呈現這些訪問者名稱。

這種方法對我來說效果很好 - 對於經典的OO設計有些短視,特別是對於帶有插入式組件的大型系統。國際海事組織,在這裏檢查笨重的類型是一大拖累,但靈活性使它值得。

0

你想要在這裏完成的一般想法正是EAV模式解決的問題。 EAV是數據庫開發中最常用的模式,但其概念對於應用程序同樣有效。