C#继承设计模式问题

时间:2009-10-14 22:26:52

标签: c# design-patterns inheritance static

我正在以不同的格式和长度存储数据。我有一个类层次结构来表示这个:

abstract class BaseDataFormat{ 
    abstract void InitalizeFromBytes(byte [] );
}

class DataFormat1 : BaseDataFormat{...}  // data stored in 3 bytes
class DataFormat2 : BaseDataFormat{...} /// data stored in 4 bytes

当我读取数据时(比如从byte []中读取),我需要知道要读取的长度(字节数)并适当地创建相应的类型。 DataFormat1和DataFormat2具有不同的长度,因此如何在运行时获取此信息?即

Fcn<DATAFORMATTYPE>(...)
 where DATAFORMATTYPE: BaseDataFormat, new();
{

DATAFORMATTYPE tmp = new DATAFORMATTYPE();
tmp.InitalizeFromBytes(ReadFromByteBuffer( ... someLength));

}

如何根据DATAFORMATTYPE对要读取的正确字节数进行编码?每个的长度感觉它应该是数据格式类型的静态属性,但静态属性不能被派生类覆盖,所以我不知道如何做到这一点。

长度可以编码为实例属性,但这似乎应该是在类级别(即静态)编码的知识。是否有设计模式来解决这个问题?

由于

5 个答案:

答案 0 :(得分:2)

也许在BaseDataFormat中有一个名为DataLength的属性。要强制所有继承者设置值,请在BaseDataFormat的构造函数中取长度,然后将该属性设置为数据长度。

示例:

abstract class BaseDataFormat
{ 
    BaseDataFormat(int dataLength)
    {
        DataLength = dataLength;
    }

    public int DataLength { get; private set; }
    abstract void InitalizeFromBytes(byte [] );
}

class DataFormat1 : BaseDataFormat
{
    public DataFormat1() : base(3)
    {
        // ...
    }
}

当然,它不是静态级别,但它是强制所有继承者的东西。

另一种方式是VirtualBlackFox如何建议,用属性装饰类。唯一的问题是AFAIK你不能强迫属性进入类,比如抽象成员。

答案 1 :(得分:2)

您如何知道在读取数据时要实例化的子类?从串行数据创建对象的更通用的解决方案是使用工厂模式。

可在以下位置找到此示例:http://en.wikipedia.org/wiki/Factory_method_pattern#Encapsulation

答案 2 :(得分:1)

我会为每个DataFormat构建Factory对象。或者可以将DataFormat作为工厂,并调用实际数据对象Datum或类似的东西。然后你可以实例化工厂,并传递字节缓冲区,它可以读取必要的字节并构造实际的数据对象。

答案 3 :(得分:0)

如果真的想要强制它是类的属性而不是实例的属性,则最好使用类上的属性。

但是你需要建立一个缓存,因为与直接访问相比,反射速度非常慢。

[AttributeUsage(AttributeTargets.Class)]
class ByteCountAttribute : Attribute
{
    public int Value { get; private set; }
    public ByteCountAttribute(int count)
    {
        Value = count;
    }
}

[ByteCount(5)]
class DataFormat1 : BaseDataFormat{}  // data stored in 3 bytes
[ByteCount(6)]
class DataFormat2 : BaseDataFormat{} /// data stored in 4 bytes

static Dictionary<Type, int> s_typeCache = new Dictionary<Type,int>();
public static int GetByteCount<T>() where T : BaseDataFormat
{
    int result;
    var type = typeof(T);
    if (!s_typeCache.TryGetValue(type, out result))
    {
        var atts = type.GetCustomAttributes(typeof(ByteCountAttribute), false);
        result = ((ByteCountAttribute)atts[0]).Value;
        s_typeCache.Add(type, result);
    }
    return result;
}

(代码没有错误管理,但它可以工作)

正如darkassassin93所说,这种方法的一个问题是你不能强制执行它的存在,所以你必须记录这个属性是必要的,这与编译器为你完成工作的抽象属性相反。

答案 4 :(得分:0)

您所追求的称为通用值适配器。您可以定义一堆只公开某些常量的类,例如:

public static class Dimensions
{
  public readonly struct Two : IInteger
  {
    public int Value => 2;
  }

  public readonly struct Three : IInteger
  {
    public int Value => 3;
  }
}

然后,您可以定义一个类,该类将这些 IInteger 类型之一作为类型参数,并在运行时简单地提取它们的值:

public class Vector<T, D>
  where D : IInteger, new()
{
  protected T[] data;

  public Vector()
  {
    data = new T[new D().Value];
  }
}

您可以将其用作

var x = new Vector<float, Dimensions.Two>();