前言:
最近有时间看看设计模式方面的书,好多东西时间久了不看就开得生疏起来, 在这里会抽出时间把自己在工作中使用过的设计模式做下总结。
刚才在看到别人说,简单工厂模式【通过提供单独的一个类,来实现创建实例对象的过程】,可以使用反射来替换掉程序中的switch/if..else,嗯,这是没问题的,但实际应用中,在移动端还要尽量少的去频繁使用反射Reflection,严重依赖字符串的功能都会存在效率的问题。
今天在看到策略模式(Strategy Pattern)的时候,突然间意识到自己在16年的一个项目中,有一处应用不够合理。
当时在存储游戏数据部分,我是通过直接将对象图转化成字节流的形式,即序列化。
那么序列化有多种方式,你可以序列化成XML,也可以是二进制,或者是SOAP(类似于XML,不建议使用,只是为了多提供一个策略演示)
那么这时候,采用哪种设计模式?
当时使用的是抽象工厂,但实际上,他更符合策略模式。即我们将多个“策略”
抽象成接口的形式来解耦合,比如说我要回大连,我可以坐火车,飞机,客车,或是自驾。我最终的目的是相同的,只是到达目的的方式不同。
然而在代码上,策略模式和抽象工厂区别不大,后来我搜索了一下关于两个设计模式之间的区别,找到了一个非常好的解释 。
策略模式vsr抽象工厂的区别
https://bbs.csdn.net/topics/320073328
2009年的一个帖子。
解释如下:
抽象工厂属于创建型的,而策略模式属于行为型。
抽象工厂往往是抽取的同一基类(Class)的不同子类。
策略模式往往抽取的是同一接口的不同实现。
那么显然,我在序列化的时候,我序列化为哪种格式,只是行为不同(纯行为上),结果相同,而且也符合同一接口的不同实现。
那么说到这里了,就把之间的代码给修改一下,修改为策略模式。
定义序列化接口:
ISerializable.cs
public interface ISerializable {
void Serialize<T> (string filePath, T data);
T Deserialize<T> (string filePath);
}
声明了两个方法,序列化和反序列化。
下面实现接口,分别是Binary,XML,SOAP
BinarySerialized.cs
using System.IO;
using System;
using System.Xml;
using System.Runtime.Serialization.Formatters.Binary;
public class BinarySerialized : ISerializable {
public void Serialize<T> (string filePath, T data)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, data);
}
}
public T Deserialize<T> (string filePath)
{
if (!File.Exists(filePath))
{
return default(T);
}
// return base.Deserialize<T>();
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter();
T data = (T)bf.Deserialize(fs);
if (data != null)
{
return data;
}
}
return default(T);
}
}
XMLSerialized .cs
using System.IO;
using System.Xml;
using System.Xml.Serialization;
public class XMLSerialized : ISerializable {
public void Serialize<T> (string filePath, T data)
{
using (XmlTextWriter xWrite = new XmlTextWriter(filePath, null))
{
XmlSerializer sl = new XmlSerializer(data.GetType());
sl.Serialize(xWrite, data);
}
}
public T Deserialize<T> (string filePath)
{
if (!File.Exists(filePath))
{
return default(T);
}
using (XmlReader xRead = new XmlTextReader(filePath))
{
XmlSerializer sl = new XmlSerializer(typeof(T));
T data = (T)sl.Deserialize(xRead);
if (data != null)
{
return data;
}
}
return default(T);
}
}
SOAPSerialized.cs(SOAP要引入dll[System.Runtime.Serialization.Formatters.Soap.dll])
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
public class SOAPSerialized : ISerializable {
public void Serialize<T> (string filePath, T data)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
SoapFormatter bf = new SoapFormatter();
bf.Serialize(fs, data);
}
}
public T Deserialize<T> (string filePath)
{
if (!File.Exists(filePath))
{
return default(T);
}
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
SoapFormatter bf = new SoapFormatter();
T data = (T)bf.Deserialize(fs);
if (data != null)
{
return data;
}
}
return default(T);
}
}
演示代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SerializedDemo: MonoBehaviour {
public SerializableContext context;
private string FILE_PATH;
DataManager data;
// Use this for initialization
void Start () {
FILE_PATH = Application.persistentDataPath + "/test20180825";
data = new DataManager();
}
// Update is called once per frame
void Update () {
}
public void OnGUI()
{
if (GUILayout.Button ("Serialized XML")) {
context =new SerializableContext (new XMLSerialized());
context.ExecuteSerialize (FILE_PATH, data);
}
if (GUILayout.Button ("Serialized Binary")) {
context =new SerializableContext (new BinarySerialized());
context.ExecuteSerialize (FILE_PATH, data);
}
if (GUILayout.Button ("Serialized SOAP")) {
context =new SerializableContext (new SOAPSerialized());
context.ExecuteSerialize (FILE_PATH, data);
}
if (GUILayout.Button ("Deserialized")) {
DataManager d = context.ExecuteDeserialize<DataManager>(FILE_PATH);
if (d != null)
{
d.debug();
}
}
}
}
[System.Serializable]
public class DataManager
{
List<Person> personList;
List<PetData> petList;
public DataManager()
{
personList = new List<Person>();
Person person1 = new Person();
person1.id = 1;
person1.name = "one";
Person person2 = new Person();
person2.id = 2;
person2.name = "two";
personList.Add(person1);
personList.Add(person2);
petList = new List<PetData>();
PetData pet1 = new PetData();
pet1.id = 10;
pet1.name = "john";
pet1.petQuality = 1;
PetData pet2= new PetData();
pet2.id = 20;
pet2.name = "lucy";
pet2.petQuality = 2;
PetData pet3 = new PetData();
pet3.id = 30;
pet3.name = "david";
pet3.petQuality = 3;
petList.Add(pet1);
petList.Add(pet2);
petList.Add(pet3);
}
public void debug()
{
foreach (Person p in personList)
{
Debug.Log(p.ToString());
}
foreach (PetData p in petList)
{
Debug.Log(p.ToString());
}
}
}
[System.Serializable]
class Person
{
public int id;
public string name;
public string ToString()
{
return "Person:id:" + id.ToString() + ",name:" + name;
}
}
[System.Serializable]
class PetData
{
public int id;
public string name;
public int petQuality;
public string ToString()
{
return "PetData:id:" + id.ToString() + ",name:" + name+",quality:"+petQuality.ToString();
}
}
在这里定义了一个DataManager类,里成包括了
List<Person> personList;
List<PetData> petList;
两个字段,并进行下初始化,然后进行序列化。
image.png演示代码下载(微云):
网友评论