1

我正在开发一款游戏,在一个名为WorldState的类中维护其信息。世界上的每个游戏对象(树木,僵尸,玩家,健康包等)由三个对象组成:GameObjectController,GameObjectModelGameObjectView。 (如果游戏对象需要附加功能,这些类可以扩展。)这是一个持久状态的好接口吗?

WorldState提供了用于加载和保存GameObjects的接口IPersistentState的实现。目前,IPersistentState的实现是ReadWriteXML,它使用XML。我担心IPersistentState接口过于耦合使用XML - 如果我要切换到使用数据库或csv或其他类型,可能需要更改它。我认为我没有创造出足够的抽象。

IPersistentState接口:

/// <summary> 
/// Used to read and write from persistent memory. 
/// 
/// When dictionaries are returned, they are key-value pairs: 
///  dict["key"] == value 
///  
/// Reading is done from whatever the current URI is. 
/// </summary> 
// This is too hard coded to XML. 
public interface IPersistentState 
{ 
    /// <summary> 
    /// Gets the KV for every object of element `elementName`. 
    /// Really this is just a convenience/wrapper method for `GetAllOfTypeIn()` 
    /// where the ancestor is the root. 
    /// </summary> 
    /// <param name="elementName">the element of object to get, like "zombie" or "point"</param> 
    /// <returns>(See interface summary) 
    ///    For Zombie, it could look like this: 
    /// 
    ///    dict["positionX"] == "23" 
    ///    dict["positionY"] == "4" 
    ///    
    ///    etc 
    /// </returns> 
    ICollection<IDictionary<string, string>> GetAllOfType(string elementName); 

    /// <summary> 
    /// Creates or overwrites the file `fileName`, filling it with the data in `dicts`. 
    /// The root of the data is `rootName`. 
    /// </summary> 
    /// <param name="dicts"></param> 
    /// <param name="rootName"></param> 
    /// <param name="fileName"></param> 
    void Write(ICollection<IDictionary<string, string>> dicts, string rootName, string fileName); 

    /// <summary> 
    /// Appends the information in `dict` to the end of the current file, under the element `elementName`. 
    /// </summary> 
    /// <param name="dict">The key-value pairs to append to the file identified by the current URI</param> 
    /// <param name="elementName">The root of the key-value pairs to append</param> 
    void Append(IDictionary<string, string> dict, string elementName); 

    /// <summary> 
    /// Sets the current URI from which to read. 
    /// </summary> 
    /// <param name="uri">Presumed to be in the Data/ directory.</param> 
    // not generic? 
    void SetURI(string uri); 

    /// <summary> 
    /// Gets the KV for every object of element `elementName`. 
    /// The search is constrainted to within `ancestor`. 
    /// </summary> 
    /// <param name="elementName">The element to look for</param> 
    /// <param name="ancestor">The element in which to search</param> 
    /// <returns>(See GetAllOfType)</returns> 
    ICollection<IDictionary<string, string>> GetAllTypeIn(string elementName, string ancestor); 
} 

这里是一个WorldState装载方法使用例子:

 persistentState.SetURI(configURI); 
     ICollection<IDictionary<string, string>> levelVariantURIDicts = persistentState.GetAllOfType("levelVariant"); 

     // OH YEAH LINQ!! 
     levelVariantURIs = levelVariantURIDicts.Select(dict => dict["filePath"]).Distinct().ToList(); 

configURI点这里:

<config> 
    <levelVariant> 
    <filePath>SampleVariant</filePath> 
    </levelVariant> 
    <levelVariant> 
    <filePath>LegendaryMode</filePath> 
    </levelVariant> 
    <levelVariant> 
    <filePath>AmazingMode</filePath> 
    </levelVariant> 
</config> 

你觉得这个怎么样?也许这种抽象不适用于数据库,但它可能适用于不同的文件类型?也许我应该只希望项目总是使用XML?我如何改变这个使它更通用?

回答

1

从你的问题的措辞来看,这听起来像你已经明白这一点,只是不知道该走哪条路,但我会以“我认为你该怎么做”的形式回答。

如果你想要一个真正抽象的数据访问层接口,你需要定义你的模型,然后建立你的模型接口,而不是任何特定的实现。例如,您在接口方法中有rootName,fileName,elementName作为参数,这听起来像您在编写XML时正在考虑XML。

不要考虑实现,应考虑每个方法如何影响模型,然后让接口的实现担心如何实际存储和更改基础数据。例如,如果您的模型具有层次性,则根据特定于域(您的游戏)的术语定义层次结构的级别,然后使用这些术语来定义通用接口。

因此,也许你的模型具有如下的结构:

Player 
    Player Attribute 
    Player Possessions 
    Player Score 
    City 
    Building 
     Objects 
     Immutable Object 
      Object property 
     Mutable Object 
      Object Property 
      Object Action 

那么你的接口方法应该使用这些概念。

所以,你可以定义一个方法来节省一些组玩家的属性,如:

void SavePlayerAttributes(string playerName, ICollection<IDictionary<string, string>> attributeNamesAndValues); 

或方法在某个位置创建一个新的对象:

void CreateImmutableObject(string cityName, string buildingName, ILocationCoordinates coordinates, IObjectPropertySet objectProperties); 

很粗糙,但希望你明白这个主意。

0

我倾向于认为当前的实现是好的,现在因为:

  1. 很难预料的变化,你会在将来让你可能有更重要的事情要专注于现在比过早的抽象。
  2. 您已经拥有了IPersistentState抽象,所以如果您确实需要稍后更改实现,那么当时应该不会太难。
  3. 对于其他存储介质,XML不一定是不好的格式。例如,如果仅将其用于序列化/反序列化并且不需要数据内部的结构化查询,则它可以是存储在数据库中的完全合理的格式。