C#继承设计模式问题
Posted
技术标签:
【中文标题】C#继承设计模式问题【英文标题】:C# inheritance design-pattern question 【发布时间】:2010-12-06 20:41:43 【问题描述】:我正在存储不同格式和长度的数据。我有一个类层次结构来表示这一点:
abstract class BaseDataFormat
abstract void InitalizeFromBytes(byte [] );
class DataFormat1 : BaseDataFormat... // data stored in 3 bytes
class DataFormat2 : BaseDataFormat... /// data stored in 4 bytes
当我读取数据时(比如从字节 []),我需要知道长度(字节数)以适当地读取和创建相应的类型。 DataFormat1 和 DataFormat2 的长度不同,那么如何在运行时获取这些信息呢?即。
Fcn<DATAFORMATTYPE>(...)
where DATAFORMATTYPE: BaseDataFormat, new();
DATAFORMATTYPE tmp = new DATAFORMATTYPE();
tmp.InitalizeFromBytes(ReadFromByteBuffer( ... someLength));
如何根据 DATAFORMATTYPE 对要读取的正确字节数进行编码?每个的长度感觉应该是数据格式类型的静态属性,但是静态属性不能被派生类覆盖,所以我不知道该怎么做。
长度可以编码为实例属性,但这似乎应该是在类级别(即静态)编码的知识。有没有设计模式可以解决这个问题?
谢谢
【问题讨论】:
【参考方案1】:也许在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 你不能将属性强制到一个类上,就像抽象成员一样。
【讨论】:
【参考方案2】:你怎么知道读取数据时要实例化哪个子类?从串行数据创建对象的更通用的解决方案是使用工厂模式。
这方面的一个例子是在:http://en.wikipedia.org/wiki/Factory_method_pattern#Encapsulation
【讨论】:
【参考方案3】:我将为每个 DataFormat 构建 Factory 对象。或者也许让DataFormat
成为工厂,并调用实际的数据对象Datum
或类似的东西。然后你可以实例化工厂,并将字节缓冲区传递给它,它可以读取必要的字节并构造实际的数据对象。
【讨论】:
我喜欢这种方法。当您不想被实例化的细节束缚时的好模式;并且可以将字节缓冲区传递给它并让它弄清楚。 无论特定问题(在哪里存储字节数)的内部解决方案是什么,工厂模式都非常明显。【参考方案4】:如果您真的想要强制它是类的属性而不是实例的属性,那么最好在类上使用属性。
但是您需要从中构建缓存,因为与直接访问相比,反射非常慢。
[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 所说,这种方法的一个问题是你不能强制它的存在,所以你必须证明这个属性是必要的,而不是编译器为你完成工作的抽象属性。
【讨论】:
【参考方案5】:您所追求的称为通用值适配器。您可以定义一堆只公开某些常量的类,例如:
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>();
【讨论】:
以上是关于C#继承设计模式问题的主要内容,如果未能解决你的问题,请参考以下文章
在设计 C# 类库时,我应该何时选择继承而不是接口? [关闭]
C# 自定义控件无法查看视图设计:文件中的类都不能进行设计,因此未能为该文件显示设计器
c#类中定义public virtual ListItem SelectedItem get; 只能get不可以set,请问有啥方式可以set么?