Unity应用架构设计(9)——构建统一的 Repository

谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化。Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化数据的行为。开发者只要对接口进行特定的实现就能够知足对不一样存储介质的访问,好比存储在Database,File System,Cache等等。软件开发领域有很是多相似的想法,好比JDBC就是定义了一套规范,而具体的厂商MySql,Oracle根据此开发对应的驱动。git

Unity 中的Repository模式

在Unity 3D中,数据的存储其实有不少地方,好比最多见的内存能够高速缓存一些临时数据,PlayerPrefs能够记录一些存档信息,TextAsset能够存一些配置信息,日志文件能够用IO操做写入,关系型数据结构可使用Sqlite存储。Repository 是个很抽象的概念,操做的数据也不必定要在本地,颇有多是存在远程服务器,因此也支持以Web Service的形式对数据进行访问和持久化。程序员

根据上述的描述,Repository 模式的架构图以下所示:github

能够看到,经过统一的接口,能够实现对不一样存储介质的访问,甚至是访问远程数据。数据库

定义Repository规范

Repository的规范就是接口,这个接口功能很简单,封装了数据增,删,查,改的行为:缓存

public interface IRepository<T> where T:class,new() {
    void Insert(T instance);
    void Delete(T instance);
    void Update(T instance);
    IEnumerable<T> Select(Func<T,bool> func );
}复制代码

这只是一个最基本的定义,也是最基础的操做,彻底能够再作扩展。服务器

值得注意的是,对于一些只读数据,好比TextAssets,Insert,Delete,Update 每每不用实现。这就违反了『里式替换原则』,解决方案也很简单,使用接口隔离,对于只读的数据只实现 ISelectable 接口。但这每每会破环了咱们的Repository结构,你可能会扩展不少不一样的行为接口,从代码角度很优化,但可读性变差。因此,在uMVVM框架中,我为了保证Repository的完整性和可读性,选择违背『里式替换原则』。数据结构

开发者根据不一样的存储介质,决定不一样的操做方法,这是显而易见的,下面就是一些常见Repository实现。架构

定义UnityResourcesRepository:用来访问Unity的资源TextAssets框架

public class UnityResourcesRepository<T> : IRepository<T> where T : class, new() {
    //...省略部分代码...
    public IEnumerable<T> Select(Func<T, bool> func)
    {
        List<T> items = new List<T>();
        try
        {
            TextAsset[] textAssets = Resources.LoadAll<TextAsset>(DataDirectory);
            for (int i = 0; i < textAssets.Length; i++)
            {
                TextAsset textAsset = textAssets[i];
                T item = Serializer.Deserialize<T>(textAsset.text);
                items.Add(item);
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.ToString());
        }
        return items.Where(func);
    }
}复制代码

定义PlayerPrefsRepository:用来访问和持久化一些存档相关信息优化

public class PlayerPrefsRepository<T> : IRepository<T> where T : class, new() {
    //...省略部分代码...
    public void Insert(T instance) {
        try
        {
            string serializedObject = Serializer.Serialize<T>(instance, true);
            PlayerPrefs.SetString(KeysIndexName, serializedObject);

        }
        catch (Exception e)
        {
            throw new Exception(e.ToString());
        }

    }

}复制代码

定义FileSystemRepository:用来访问和持久化一些日志相关信息

public class FileSystemRepository<T> : IRepository<T> where T:class,new() {    
    //...省略部分代码...
    public void Insert(T instance) {
        try
        {
            string filename = GetFilename(Guid.NewGuid());
            if (File.Exists(filename))
            {
                throw new Exception("Attempting to insert an object which already exists. Filename=" + filename);
            }

            string serializedObject = Serializer.Serialize<T>(instance, true);
            using (StreamWriter stream = new StreamWriter(filename))
            {
                stream.Write(serializedObject);
            }
        }
        catch (Exception e)
        {
            throw new Exception(e.ToString());
        }

    }

}复制代码

定义MemoryRepository:用来高速缓存一些临时数据

public class MemoryRepository<T> : IRepository<T> where T : class, new()
{

    //...省略部分代码...

    private Dictionary<object, T> repository = new Dictionary<object, T>();

    public MemoryRepository()
    {
        FindKeyPropertyInDataType();
    }

    public void Insert(T instance)
    {
        try
        {
            var id = KeyPropertyInfo.GetValue(instance, null);
            repository[id] = instance;
        }
        catch (Exception e)
        {
            throw new Exception(e.ToString());
        }
    }

    private void FindKeyPropertyInDataType()
    {
        foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
        {
            object[] attributes = propertyInfo.GetCustomAttributes(typeof(RepositoryKey), false);
            if (attributes != null && attributes.Length == 1)
            {
                KeyPropertyInfo = propertyInfo;
            }
            else
            {
                throw new Exception("more than one repository key exist");
            }
        }

    }
}复制代码

定义DbRepository:用来操做关系型数据库Sqlite

public class DbRepository<T> : IRepository<T> where T : class, new() {
    private readonly SQLiteConnection _connection;

    //...省略部分代码...

    public void Insert(T instance) {
        try
        {
            _connection.Insert(instance);
        }
        catch (Exception e)
        {
           throw new Exception(e.ToString());
        }
    }

}复制代码

定义RestRepository:以WebService的形式访问和持久化远程数据

public class RestRepository<T, R>:IRepository<T> where T : class, new() where R : class, new()
{
    //...省略部分代码...

    public void Insert(T instance)
    {
        //经过WWW像远程发送消息
    }
}复制代码

小结

Repository 模式是很常见的数据层技术,对于.NET 程序员来讲就是DAL,而对于Java程序员而言就是DAO。咱们扩展了不一样的Repository 对象来对不一样的介质进行访问和持久化,这也是从此对缓存的实现作准备。
源代码托管在Github上,点击此了解

欢迎关注个人公众号:

相关文章
相关标签/搜索