2008-09-08 19 views
3

Donc, si j'ai une méthode d'analyse d'un fichier texte et retourner une liste d'unelistedepaires de valeurs clés, et que vous voulez créer des objets à partir des KVPS renvoyés (chaque liste de KVPS représente un objet différent), quelle serait la meilleure méthode?Qu'est-ce qu'un bon design lorsque vous essayez de construire des objets à partir d'une liste de paires de valeurs clés?

La première méthode qui apparaît à l'esprit est assez simple, il suffit de garder une liste de mots-clés:

private const string NAME = "name"; 
private const string PREFIX = "prefix"; 

et vérifier contre les touches que je reçois pour les constantes que je veux, définies ci-dessus. C'est une partie assez fondamentale du projet sur lequel je travaille, donc je veux bien le faire; est-ce que quelqu'un a des suggestions plus robustes (ne pas dire qu'il y a quelque chose de fondamentalement non-robuste au sujet de la méthode ci-dessus - je demande juste autour)?

Editer:

Plus de détails ont été demandés. Je travaille sur un petit jeu dans mon temps libre, et je construis le monde du jeu avec des fichiers de configuration. Il y en a quatre - l'un définit toutes les créatures, l'autre définit toutes les zones (et leur emplacement dans une carte), un autre tous les objets et un dernier définit diverses options de configuration et d'autres qui ne correspondent pas ailleurs. Avec les trois premiers fichiers de configuration, je vais créer des objets basés sur le contenu des fichiers - ce sera très lourd, il y aura beaucoup de chaînes, des choses comme des noms, des pluriels, des préfixes - ce genre de choses. Les valeurs de configuration sont toutes semblables:

- 
key: value 
key: value 
- 
key: value 
key: value 
- 

Lorsque la ligne '-' indique une nouvelle section/objet.

Répondre

1

Vous pouvez créer une interface qui correspond aux noms de colonnes, puis utiliser l'API Reflection.Emit pour créer un type lors de l'exécution qui a donné accès aux données dans les champs.

3

Jetez un coup d'œil au . Même si vous êtes contraint de ne pas utiliser XML sur disque, vous pouvez copier certaines de ses fonctionnalités. Cela pourrait ressembler à ceci:

public class DataObject { 
    [Column("name")] 
    public string Name { get; set; } 

    [Column("prefix")] 
    public string Prefix { get; set; } 
} 

Attention cependant d'inclure une sorte de version du format dans vos fichiers, ou vous serez dans la cuisine de l'enfer viennent le prochain changement de format.

2

De quoi avez-vous besoin? De la façon dont vous le décrivez, vous les utiliserez comme une carte restreinte (de type clé) de toute façon. Si vous n'avez pas besoin d'une sorte d'héritage, je voudrais simplement envelopper une structure similaire à une carte dans un objet comme celui-ci:

[java-inspired pseudo-code:]
class RestrictedKVDataStore { 
    const ALLOWED_KEYS = new Collection('name', 'prefix'); 
    Map data = new Map(); 

    void put(String key, Object value) { 
     if (ALLOWED_KEYS.contains(key)) 
      data.put(key, value) 
    } 

    Object get(String key) { 
     return data.get(key); 
    } 
} 
0

@ David:
J'ai déjà l'analyseur (et la plupart d'entre eux seront écrit à la main, donc j'ai décidé contre XML). Mais cela ressemble à une façon vraiment sympa de le faire; Je vais devoir vérifier. Excellent point sur le versioning aussi.

@Argelbargel:
Cela semble bien aussi. :

3

En faisant beaucoup de suppositions injustifiées, je pense que la meilleure approche serait de créer une usine qui recevra la liste des paires de valeurs clés et retourner l'objet approprié ou lancer une exception si elle est invalide (ou créer un objet factice, ou quoi de mieux dans le cas particulier).

private class Factory { 

    public static IConfigurationObject Factory(List<string> keyValuePair) { 

     switch (keyValuePair[0]) { 

      case "x": 
       return new x(keyValuePair[1]); 
       break; 
      /* etc. */ 
      default: 
       throw new ArgumentException("Wrong parameter in the file"); 
     } 

    } 

} 

L'hypothèse peut être traitée plus forte est ici que tous vos objets en partie comme le même (ils mettent en œuvre la même interface (IConfigurationObject dans l'exemple) ou appartiennent au même arbre d'héritage).

Dans le cas contraire, il dépend de votre flux de programme et ce que vous faites avec eux. Mais néanmoins, ils devraient :)

EDIT: Compte tenu de votre explication, vous pourriez avoir une usine par type de fichier, le commutateur dans ce serait la source faisant autorité sur les types autorisés par type de fichier et ils partagent probablement quelque chose en commun. La réflexion est possible, mais c'est plus risqué parce que c'est moins évident et auto-documenté que celui-ci.

0

... Ceci est un morceau assez noyau du projet je travaille bien ...

Est-il vraiment?

Il est tentant de simplement abstraite et fournir une implémentation de base avec l'intention de refactoring plus tard.

Ensuite, vous pouvez vous concentrer sur ce qui compte: le jeu.

Juste une pensée

< bb/>

0

Est-il vraiment?

Oui; J'ai pensé cela. Loin de moi l'idée de faire plus de travail que nécessaire. : ')

1

EDIT:

Scratch qui, cela est toujours valable, mais je pense que ce que vous faites est en train de lire un fichier de configuration et l'analyse syntaxique dans ceci:

List<List<KeyValuePair<String,String>>> itemConfig = 
    new List<List<KeyValuePair<String,String>>>(); 

Dans ce cas, nous pouvons toujours utiliser une fabrique de réflexion pour instancier les objets, je passerai simplement dans la liste interne imbriquée, au lieu de passer chaque paire clé/valeur individuelle.

VIEUX POST:

Voici une manière peu intelligente de faire cette réflexion en utilisant:

L'idée de base:

  • Utilisez une classe de base commune pour chaque classe d'objets.
  • Mettez toutes ces classes dans leur propre assemblage.
  • Placez également cette usine dans cet assemblage.
  • passe dans le KeyValuePair que vous lisez votre config, et en retour, il trouve la classe qui correspond à KV.Key et instancie avec KV.Valeur
 
     public class KeyValueToObjectFactory 
     { 
     private Dictionary _kvTypes = new Dictionary(); 

     public KeyValueToObjectFactory() 
     { 
      // Preload the Types into a dictionary so we can look them up later 
      // Obviously, you want to reuse the factory to minimize overhead, so don't 
      // do something stupid like instantiate a new factory in a loop. 

      foreach (Type type in typeof(KeyValueToObjectFactory).Assembly.GetTypes()) 
      { 
       if (type.IsSubclassOf(typeof(KVObjectBase))) 
       { 
        _kvTypes[type.Name.ToLower()] = type; 
       } 
      } 
     } 

     public KVObjectBase CreateObjectFromKV(KeyValuePair kv) 
     { 
      if (kv != null) 
      { 
       string kvName = kv.Key; 

       // If the Type information is in our Dictionary, instantiate a new instance of that class. 
       Type kvType; 
       if (_kvTypes.TryGetValue(kvName, out kvType)) 
       { 
        return (KVObjectBase)Activator.CreateInstance(kvType, kv.Value); 
       } 
       else 
       { 
        throw new ArgumentException("Unrecognized KV Pair"); 
       } 
      } 
      else 
      { 
       return null; 
      } 
     } 
    }