谈到 『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的更多相关文章

  1. Unity应用架构设计(3)——构建View和ViewModel的生命周期

    对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者在各个阶段 ...

  2. Unity 3D Framework Designing(9)——构建统一的 Repository

    谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...

  3. Unity应用架构设计(11)——一个网络层的构建

    对于客户端应用程序,免不了和远程服务打交道.设计一个良好的『服务层』能帮我们规范和分离业务代码,提高生产效率.服务层最核心的模块一定是怎样发送请求,虽然Mono提供了很多C#网络请求类,诸如WebCl ...

  4. Unity应用架构设计(6)——设计动态数据集合ObservableList

    什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...

  5. Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 1)

    『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...

  6. Unity应用架构设计(1)—— MVVM 模式的设计和实施(Part 2)

    MVVM回顾 经过上一篇文章的介绍,相信你对MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在. View只关心怎样渲染,而ViewModel只 ...

  7. Unity应用架构设计(13)——日志组件的实施

    对于应用程序而言,日志是非常重要的功能,通过日志,我们可以跟踪应用程序的数据状态,记录Crash的日志可以帮助我们分析应用程序崩溃的原因,我们甚至可以通过日志来进行性能的监控.总之,日志的好处很多,特 ...

  8. Unity应用架构设计(7)——IoC工厂理念先行

    一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...

  9. Unity应用架构设计(1)—— MVVM 模式的设计和实施(Part 1)

    初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...

随机推荐

  1. 00-JAVA语法基础--课后作业

    题目:像二柱子那样,花20分钟写一个能自动生成30道小学四则运算题目的“软件”. package 课堂作业1; import java.util.Random; import java.util.Sc ...

  2. linux 学习笔记 软件包管理

    >查询文件所属软件包 #rpm -qf /usr/share/pixmaps/xplns.png 查询某个文件所属软件包 >查询软件包所包含文件列表 #rpm -ql xplus-3.3. ...

  3. 安装mysql以及修改mysql字符集问题

    1.安装mysql sudo apt-get install mysql-server sudo apt-get install mysql-client   2.部分命令: sudo service ...

  4. MVC面试问题与答案

    读这篇文章不意味着你一定要去并且能搞定MVC面试.这篇文章的目的是在面试之前让你快速复习MVC知识.这篇文章也不是MVC培训课程. 如果你想学习MVC,从这儿开始 Learn MVC ( Model ...

  5. Centos6 安装RabbitMq3.7.7

    安装包准备官网地址:    Erlang安装包下载:https://www.erlang-solutions.com/resources/download.html    RabbitMq安装包下载: ...

  6. Python基础知识—sys模块初探

    有关Python解释器的信息 与所有其他模块一样,必须使用import语句导入sys模块,即import sys. sys模块提供有关Python解释器的常量,函数和方法.dir(系统)给出了可用常量 ...

  7. [CSAcademy]Sum of Powers

    [CSAcademy]Sum of Powers 题目大意: 给定\(n,m,k(n,m,k\le4096)\).一个无序可重集\(A\)为合法的,当且仅当\(|A|=m\)且\(\sum A_i=n ...

  8. mongoose事务操作,参考官网

    https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/ await model.photo.bulkWrit ...

  9. 考前停课集训 Day6 垒

    Day 6 今天在家里的 家里蹲 其实是day7的时候想到要写day6了 草率补充一下 NOIP考前棕名退不掉咯 你觉得我还会打洛谷的题目吗? 依然退步 没用心 T1 分火腿 数论题 我感觉挺难的 T ...

  10. unity 动画无法正常播放Animation的动画问题

    1,百度得来的一种方案,留作备用: 有一个区别的地方在于新建动画之前,选中物体身上有无Animation组件: 1.没有的话,选中物体,打开Animation窗口,新建,会出现一个animation一 ...