2009-07-01 134 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是数据库开发中最常用的模式,但其概念对于应用程序同样有效。