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上,點擊此瞭解

歡迎關注個人公衆號:

相關文章
相關標籤/搜索