项目音之国度用到了读存档,需要把一些运行时要用到的信息存起来。
初步设计信息如下:
玩家拥有的道具信息——int类型的索引数组。
玩家当前经验值——int。
玩家当前等级——int。
音符兽的形态——int。
音符兽对主人的好感度——int。
当前拥有的是哪些音符兽——int。
初步计划是编写一个可拓展性很强的类库,因为读存档的信息太容易变化了。
理一理思路,其实能够发现,一共三步,将数据结构的信息全转成string——加密string——利用XML将string存起来(反向加载的时候亦然)。
很容易得知,类库中比较易变的是第一步转码(因为会因为要存储的信息不一样而改变),第二步加密,因为不同的策略而改变方法。
所以我们首先抽象出一个泛型接口DataElement<T>:
public interface DataElememt<T> where T :new()
{
string DataToFile(T _t);
T FileToData(string _s);
T Instance ();
};
再来就是加密策略接口,不同的策略将在实现类延迟实现:
public interface AccessStrategy<T>where T :new()
{
string Access(T _t,DataElememt<T> dataElements);
T Load(string s,DataElememt<T> dataElements);
};
接下来我们会发现具体实现数据读存档的类已经可以写了:
public class DataManager<T>where T :new()
{
AccessStrategy<T> _Strategy;
string _file;
DataElememt<T> _dataElement;
public DataManager(AccessStrategy<T> strategy,DataElememt<T> dataElement,string file)
{
_Strategy = strategy;
_file = file;
_dataElement = dataElement;
}
public void Write(int _index,T _t)
{
XmlDocument xml_doc=new XmlDocument();
string _tempMessage = _Strategy.Access (_t,_dataElement);
if (File.Exists (_file))
{
xml_doc.Load (_file);
XmlNodeList list_node=xml_doc.SelectSingleNode ("GAMEFILE").ChildNodes;
bool isHaveIndex=false;
string[] all_data=new string[list_node.Count];
string[] all_index = new string[list_node.Count];
int cp = 0;
int cl = 0;
foreach(XmlElement xn in list_node)
{
if (xn.InnerText == _index.ToString ())
{
isHaveIndex = true;
cl = cp;
}
all_data [cp] = xn.GetAttribute ("data");
all_index[cp] = xn.Name;
cp++;
}
if (isHaveIndex)
{
xml_doc = new XmlDocument ();
XmlElement Top_ELEMENT = xml_doc.CreateElement ("GAMEFILE");
xml_doc.AppendChild (Top_ELEMENT);
for(int i=0;i<cp;i++)
{
if (i != cl)
{
XmlElement xe = xml_doc.CreateElement ("FILEDATA");
xe.InnerText = all_index [i].ToString ();
xe.SetAttribute ("data",all_data[i]);
xml_doc.FirstChild.AppendChild (xe);
}
}
}
}
else
{
XmlElement Top_ELEMENT = xml_doc.CreateElement ("GAMEFILE");
xml_doc.AppendChild (Top_ELEMENT);
}
XmlElement xe1 = xml_doc.CreateElement ("FILEDATA");
xe1.InnerText = _index.ToString ();
xe1.SetAttribute ("data", _tempMessage);
xml_doc.FirstChild.AppendChild (xe1);
xml_doc.Save (_file);
}
public void Clear()
{
XmlDocument xml_doc=new XmlDocument();
xml_doc.Save (_file);
}
public T Read(int _index)
{
XmlDocument xml_doc=new XmlDocument();
xml_doc.Load (_file);
T _result = _dataElement.Instance ();
XmlNodeList list_node=xml_doc.SelectSingleNode ("GAMEFILE").ChildNodes;
foreach(XmlElement xn in list_node)
{
if (int.Parse (xn.InnerText) == _index)
{
string _temp;
_temp = xn.GetAttribute ("data");
_result = _Strategy.Load (_temp, _dataElement);
break;
}
}
return _result;
}
};
组合了转码类和加密类,这个类实际上就是利用xml读写,将转码和加密这两个部分桥接了起来,类似设计模式中的桥梁模式。其实像一个系统中的若干功能如果都能发生独立的变化,我们可以利用各自提供一个接口,最后再在总的系统中做桥接,这样子类的数量非常少,而且耦合性低。