Unity 3D Framework Designing(9)——构建统一的 Repository
谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化。Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化数据的行为。开发者只要对接口进行特定的实现就可以满足对不同存储介质的访问,比如存储在Database,File System,Cache等等。软件开发领域有非常多类似的想法,比如JDBC就是定义了一套规范,而具体的厂商MySql,Oracle根据此开发对应的驱动。
Unity 中的Repository模式
在Unity 3D中,数据的存储其实有很多地方,比如最常见的内存可以高速缓存一些临时数据,PlayerPrefs可以记录一些存档信息,TextAsset可以存一些配置信息,日志文件可以用IO操作写入,关系型数据结构可以使用Sqlite存储。Repository 是个很抽象的概念,操作的数据也不一定要在本地,很有可能是存在远程服务器,所以也支持以Web Service的形式对数据进行访问和持久化。
根据上述的描述,Repository 模式的架构图如下所示:

可以看到,通过统一的接口,可以实现对不同存储介质的访问,甚至是访问远程数据。
定义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上,点击此了解
Unity 3D Framework Designing(9)——构建统一的 Repository的更多相关文章
- Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期
> 对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者 ...
- Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 2)
MVVM回顾 经过上一篇文章的介绍,相信你对 MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在.View只关心怎样渲染,而ViewModel只 ...
- Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 1)
初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity 3D Framework Designing(6)——设计动态数据集合ObservableList
什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...
- Unity 3D Framework Designing(7)——IoC工厂理念先行
一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...
- Unity应用架构设计(9)——构建统一的 Repository
谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...
- Unity 3D Framework Designing(5)——ViewModel之间如何共享数据
对于客户端应用程序而言,单页应用程序(Single Page Application)是最常见的表现形式.有经验的开发人员往往会把一个View分解多个SubView.那么,如何在多个SubView之间 ...
- Unity 3D Framework Designing(2)——使用中介者模式解耦ViewModel之间通信
当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件).越是复杂的页面,被切割出来的子模块就越多,子模块 ...
随机推荐
- js与android webview交互
0x01 js调用java代码 android webview中支持通过添加js接口 webview.addJavascriptInterface(new JsInteration(), " ...
- JavaScript严格模式说明带示例
严格模式(use strict) 目的 消除JS中一些不合理.不严谨之处,减少一些怪异行为 消除代码中的一些不安全之处,保障代码运行安全 提高编译器效率,增加运行速度 为以后的JS新规范做铺垫 兼容性 ...
- 前端Cookie与Session的区别
我们在实际生活中总会遇到这样的事情,我们一旦登录(首次输入用户名和密码)某个网站之后,当我们再次访问的时候(只要不关闭浏览器),无需再次登录.而当我们在这个网站浏览一段时间后,它会产生我们浏览的记录, ...
- qppium 原理解析
Appium是 c/s模式的appium是基于 webdriver 协议添加对移动设备自化api扩展而成的webdriver 是基于 http协议的,第一连接会建立个 session 会话,并通过 p ...
- 【转】Python 中 Iterator和Iterable的区别
Python中 list,truple,str,dict这些都可以被迭代,但他们并不是迭代器.为什么? 因为和迭代器相比有一个很大的不同,list/truple/map/dict这些数据的大小是确定的 ...
- 监听器如何获取Spring配置文件(加载生成Spring容器)
Spring容器是生成Bean的工厂,我们在做项目的时候,会用到监听器去获取spring的配置文件,然后从中拿出我们需要的bean出来,比如做网站首页,假设商品的后台业务逻辑都做好了,我们需要创建一个 ...
- Python入门教程(2)
人生苦短,我玩蛇0.0! Python(英语发音:/ˈpaɪθən/), 是一种面向对象.解释型计算机程序设计语言,由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991 ...
- Linux使用小笔记<进程操作篇>
问题一: 查看哪个进程占用了哪个端口.以及杀掉进程 1.查看占用端口: sudo lsof -i :80 lsof 命令 是 list open files的意思 比如: lsof filename ...
- NDK 开发(Android.mk配置)
在我写这篇文章的时候,Android Studio已经是2.3版本了,已经集成CMake 编译工具, 用户只需在 新建项目的时候,添加选项(Include C++ support),Andr ...
- python3.4 安装 scrapy 报错 VS2010
安装scrapy框架报错是常见问题 还好,本人只碰到其中一个bug,以下是此次安装经验 环境 py3.4 windows7 64位 安装有VS2010 pip包管理(pycharm) 报错信息 安装l ...