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

本文关键字:层次结构 何扩展 扩展 一个 | 更新日期: 2023-09-27 18:18:03

我有一个仅由数据组成的类层次结构。例如:

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>,所以我必须一直转换为新类型。一个更大的问题是,我还需要能够从扩展的层次结构序列化原始层次结构,当每个实例都是派生类型时,我无法做到这一点。

问题:是否有一种方法可以扩展完整的类层次结构,以便我可以在某个地方共享纯数据对象模型,并且仍然能够在不丢失原始结构的情况下在外部添加更多信息和行为?

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

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

你的问题中的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)

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

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标志来序列化有或没有扩展的层次结构。