2009-10-14 7 views
0

Je stocke des données avec différents formats et longueurs. J'ai une hiérarchie de classes pour représenter ceci:C# héritage motif-modèle question

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

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

Quand je lis mes données (par exemple à partir d'un octet []), je dois connaître la longueur (nombre d'octets) à lire et à créer le type correspondant de façon appropriée . DataFormat1 et DataFormat2 ont des longueurs différentes, alors comment obtenir ces informations lors de l'exécution? c'est à dire.

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

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

} 

Comment encoder le nombre d'octets à lire en fonction du DATAFORMATTYPE? La longueur pour chacun se sent comme il devrait être une propriété statique du type de format de données, mais les propriétés statiques ne peuvent pas être remplacées par la classe dérivée, donc je ne suis pas sûr comment faire ceci.

La longueur peut être codée comme une propriété d'instance, mais cela semble être une connaissance codée au niveau de la classe (c'est-à-dire statique). Existe-t-il un modèle de conception pour résoudre ce problème?

Merci

Répondre

2

Peut-être avoir une propriété dans BaseDataFormat appelée DataLength. Pour forcer tous les héritiers à définir une valeur, prenez la longueur au constructeur de BaseDataFormat, puis définissez cette propriété sur la longueur de données.

Exemple:

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) 
    { 
     // ... 
    } 
} 

Accordé, ce n'est pas au niveau statique, mais il est quelque chose qui est forcé pour tous les héritiers.

Une autre façon est de savoir comment VirtualBlackFox suggéré, décorer la classe avec un attribut. Le seul problème est que AFAIK vous ne pouvez pas forcer des attributs sur une classe, comme avec des membres abstraits.

0

Le meilleur si vous vraiment voulez appliquer qu'il est une propriété de la classe et non de l'instance est d'utiliser un attribut de la classe.

Mais vous aurez besoin de créer un cache à partir de cela car la réflexion est très lente par rapport à un accès direct.

[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; 
} 

(Le code a pas de gestion des erreurs, mais il fonctionne)

Comme l'a dit darkassassin93 l'un des problème avec cette approche est que vous ne pouvez pas appliquer sa présence et donc vous devez documenter que cette L'attribut est nécessaire contrairement à une propriété abstraite où le compilateur fait le travail pour vous.

1

Je créerais des objets Factory pour chaque DataFormat. Ou peut-être faire DataFormat être l'usine, et appeler les objets de données réelles Datum ou quelque chose comme ça. Ensuite, vous pouvez instancier l'usine et lui passer le tampon d'octets, et il peut lire les octets nécessaires et construire l'objet de données réel. Comment connaissez-vous la sous-classe à instancier lors de la lecture de données?

+0

J'aime cette approche.Bon motif pour quand vous ne voulez pas être attaché dans les détails de l'instanciation; et peut simplement passer le tampon octet et le laisser comprendre. – gn22

+0

Quelle que soit la solution interne à la question spécifique (où stocker le nombre d'octets), le modèle d'usine est assez évident à avoir. –