Unity应用架构设计(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应用架构设计(9)——构建统一的 Repository的更多相关文章
- Unity应用架构设计(3)——构建View和ViewModel的生命周期
对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者在各个阶段 ...
- Unity 3D Framework Designing(9)——构建统一的 Repository
谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...
- Unity应用架构设计(11)——一个网络层的构建
对于客户端应用程序,免不了和远程服务打交道.设计一个良好的『服务层』能帮我们规范和分离业务代码,提高生产效率.服务层最核心的模块一定是怎样发送请求,虽然Mono提供了很多C#网络请求类,诸如WebCl ...
- Unity应用架构设计(6)——设计动态数据集合ObservableList
什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...
- Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity应用架构设计(1)—— MVVM 模式的设计和实施(Part 2)
MVVM回顾 经过上一篇文章的介绍,相信你对MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在. View只关心怎样渲染,而ViewModel只 ...
- Unity应用架构设计(13)——日志组件的实施
对于应用程序而言,日志是非常重要的功能,通过日志,我们可以跟踪应用程序的数据状态,记录Crash的日志可以帮助我们分析应用程序崩溃的原因,我们甚至可以通过日志来进行性能的监控.总之,日志的好处很多,特 ...
- Unity应用架构设计(7)——IoC工厂理念先行
一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...
- Unity应用架构设计(1)—— MVVM 模式的设计和实施(Part 1)
初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...
随机推荐
- vue中的jsx
一.配置文件package.json { "name": "vuetest", "version": "1.0.0", ...
- Redis自学笔记:4.2进阶-过期时间
4.2过期时间 **4.2.1命令介绍* 在redis中使用 expire 命令设置一个键的过期时间后redis会自动删除它. expire key seconds (seconds单位是秒,必须是整 ...
- Java笔记(九)EnumMap & EnumSet
EnumMap & EnumSet 一.EnumMap 一)基本用法 public static Map<Size, Integer> countBySize(List<Cl ...
- Win7系统 mstsc远程桌面连接失败,提示“您的凭据不工作” 或者“无法连接到远程计算机”的问题。
WIN7 mstsc远程桌面连接其他电脑,提示"您的凭据不工作xxxxxxx"的问题. 或者提示: 本机通过mstsc远程桌面连接服务器,我们按照下面的步骤来逐一排查: 本机配置以 ...
- iOS自动布局的学习
Autolayout: 最重要的两个概念: 约束:对控件位置和大小的限定条件 参照:对控件设置的约束是相对于哪一个视图而言的 自动布局的核心计算公式: obj1.property1 =(obj2.pr ...
- List集合的总结和应用场景的介绍
1.List的整体介绍 List 是一个接口,它继承于Collection的接口,它代表着有序的队列.list的实现类对象中每一个元素都有一个索引值,能够按照索引值进行元素查找. AbstractLi ...
- NLP 工具类库
NLPIR http://www.nlpir.org/ HanLP https://github.com/hankcs Apache OpenNLP https://opennlp.apache. ...
- domReady
function myReady(fn){ //对于现代浏览器,对DOMContentLoaded事件的处理采用标准的事件绑定方式 if ( document.addEventListener ) { ...
- sql 索引笔记--索引组织结构
非聚集索引与聚集索引具有相同的 B 树结构,它们之间的显著差别在于以下两点: 基础表的数据行不按非聚集键的顺序排序和存储. 非聚集索引的叶层是由索引页而不是由数据页组成. 既可以使用聚集索引来为表或视 ...
- GMA Round 1 最大值
传送门 最大值 求$f(x)=cos(x)+\sqrt{cos^2(x)-4\sqrt{3}cos(x)+4\sqrt{2}sin(x)+10}$的最大值.保留到小数点后3位. $f(x)+\sqrt ...