如何扩展完整的树状类层次结构

时间:2013-06-12 05:37:06

标签: c# design-patterns serialization

我有一个只包含数据的类层次结构。例如:

class A 
{
    List<B> b { get; set; }
    C c { get; set; }
}

class B 
{ 
    int d { get; set; }
}

class C 
{
    List<int> e { get; set; }
}

使用XML和protobuf-net准备类层次结构以进行序列化。它也存在于一个单独的库中,因为它需要由两个不同的应用程序使用。

现在我需要创建此类层次结构的扩展版本,其中节点的数量及其关系是相同的,但每个节点中可以有额外的数据,方法或属性。例如:

class AA : A
{
    int extra { get; set; }
}

class BB : B
{
    float extra { get; set; }
    void something();
}

class CC : C
{
    float extra { get; set; }
}

我在上面看到的一个问题是,类之间的所有(继承)引用仍然使用原始层次结构中的类型,即List<B>而不是List<BB>,所以我必须转换为新的类型一直在。更大的问题是我还需要能够从扩展的层次结构化原始层次结构,当每个实例都是派生类型时,我无法做到这一点。

问题:有没有办法扩展完整的类层次结构,这样我就可以在某处拥有共享的纯数据对象模型,并且仍然能够在外部添加更多信息和行为而不会丢失原始结构?

2 个答案:

答案 0 :(得分:3)

我认为你可以使用泛型做你想做的事。至少对于防止铸造的解决方案。 我还在考虑如何从扩展的序列化序列化原始层次结构。

您问题中的B,BB,C和CC类仍然相同。

首先是通用A类:

class A<BType, CType> where BType: B where CType: C {
    List<BType> b { get; set;}
    CType c { get; set;}
}

然后使用泛型A类的非泛型A类:

class A: A<B, C> {
}

和(非泛型)AA类也使用泛型A类:

class AA: A<BB, CC> {
    int extra { get; set; }
}

答案 1 :(得分:0)

我使用 Extension Object 设计模式的简化版本解决了问题。

步骤1)

首先,我创建了以下接口和抽象基类,分别由扩展和可扩展对象使用:

public interface IExtension 
{
    bool IsSerializable { get; }
}

public abstract class Extensible
{
    public static bool ShouldSerializeExtensions = true;

    public IExtension Extension { get; set; }

    public bool ShouldSerializeExtension()
    {
        return ShouldSerializeExtensions &&
               Extension != null &&
               Extension.IsSerializable;
    }
}

静态ShoulSerializeExtensions标志允许我暂时启用或禁用整个扩展的序列化,而IsSerializable属性允许我创建根本不应序列化的扩展。

注意:在序列化之前,我还需要提供我创建的所有具体扩展类型的列表。

第2步)

我让层次结构中的每个节点都继承自Extensible,并为每个节点创建了扩展类:

public class A : Extensible
{
    List<B> b { get; set; }
    C c { get; set; }
}

public class B  : Extensible
{ 
    int d { get; set; }
}

public class C  : Extensible
{
    List<int> e { get; set; }
}

public class ExtensionA : IExtension
{
    bool IsSerializable { get { return true; } }
    int extra { get; set; }
}

public class ExtensionB : IExtension
{
    bool IsSerializable { get { return true; } }
    float extra { get; set; }
    void something();
}

public class ExtensionC : IExtension
{
    bool IsSerializable { get { return true; } }
    float extra { get; set; }
}

第3步)

我创建了一个 Factory ,以确保创建的每个节点都附加了正确的扩展对象。

public static class Factory
{
    public static A CreateA()
    {
        var a = new A();
        a.Extension = new ExtensionA();
        return a;
    }

    ...
}

我还创建了扩展方法,使得操作扩展更容易,而不必每次都转换为正确的类型。

public static class ExtensionUtils
{
    public static ExtensionA GetExtension(this A a)
    {
       return a.Extension as ExtensionA;
    }

    ...
}

示例)

一切就绪后,我可以创建一个扩展对象并更改其值,如下所示:

var a = Factory.CreateA();
a.GetExtension().extra = 20;

通过在序列化之前设置全局Extensible.ShouldSerializeExtensions标志,我可以使用或不使用扩展来序列化层次结构。