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 模式的架构图如下所示:

o_Untitled.png

可以看到,通过统一的接口,可以实现对不同存储介质的访问,甚至是访问远程数据。

定义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上,点击此了解

88x31.png
本博客为 木宛城主原创,基于 Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 木宛城主(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。

本文转自木宛城主博客园博客,原文链接:http://www.cnblogs.com/OceanEyes/p/thinking_in_repository_pattern.html,如需转载请自行联系原作者
目录
相关文章
|
5天前
|
敏捷开发 监控 数据管理
构建高效微服务架构的五大关键策略
【4月更文挑战第20天】在当今软件开发领域,微服务架构已经成为一种流行的设计模式,它允许开发团队以灵活、可扩展的方式构建应用程序。本文将探讨构建高效微服务架构的五大关键策略,包括服务划分、通信机制、数据管理、安全性考虑以及监控与日志。这些策略对于确保系统的可靠性、可维护性和性能至关重要。
|
15天前
|
机器学习/深度学习 API 语音技术
|
6天前
|
消息中间件 监控 持续交付
构建高效微服务架构:后端开发的进阶之路
【4月更文挑战第20天】 随着现代软件开发的复杂性日益增加,传统的单体应用已难以满足快速迭代和灵活部署的需求。微服务架构作为一种新兴的分布式系统设计方式,以其独立部署、易于扩展和维护的特点,成为解决这一问题的关键。本文将深入探讨微服务的核心概念、设计原则以及在后端开发实践中如何构建一个高效的微服务架构。我们将从服务划分、通信机制、数据一致性、服务发现与注册等方面入手,提供一系列实用的策略和建议,帮助开发者优化后端系统的性能和可维护性。
|
1天前
|
Cloud Native Devops 持续交付
构建未来:云原生架构在企业数字化转型中的关键作用
【4月更文挑战第24天】 随着企业加速其数字化转型之旅,云原生架构已成为实现敏捷性、可扩展性和持续创新的关键推动力。本文将探讨云原生技术如何助力企业构建灵活的IT环境,支持快速部署新服务,并提高整体业务效率。通过分析微服务、容器化、DevOps和持续集成/持续部署(CI/CD)等关键技术的实践应用,我们将揭示这些元素如何共同塑造出一个响应迅速且高效的企业架构模型。
|
1天前
|
持续交付 API 开发者
构建高效微服务架构:后端开发的新范式
【4月更文挑战第24天】 随着现代软件系统的复杂性日益增加,传统的单体应用已难以满足快速迭代与灵活扩展的需求。微服务架构作为一种新兴的软件开发模式,以其服务的细粒度、独立部署和弹性伸缩等优势,正在逐渐成为后端开发的重要趋势。本文将深入探讨微服务架构的设计原则、关键技术以及在实际业务中的应用实践,旨在为后端开发者提供构建和维护高效微服务架构的参考指南。
|
3天前
|
监控 API 持续交付
构建高效微服务架构:后端开发的新趋势
【4月更文挑战第23天】 随着现代软件开发实践的不断演进,微服务架构已经成为企业追求敏捷、可扩展和弹性解决方案的首选。本文深入探讨了如何构建一个高效的微服务架构,涵盖了关键的设计原则、技术选型以及实践建议。通过分析微服务的独立性、分布式特性和容错机制,我们将揭示如何利用容器化、服务网格和API网关等技术手段,来优化后端系统的可维护性和性能。文章旨在为后端开发人员提供一套全面的指南,以应对不断变化的业务需求和技术挑战。
|
5天前
|
Cloud Native API 持续交付
构建未来:云原生架构在企业数字化转型中的关键作用
【4月更文挑战第21天】 随着企业加速其数字化转型的步伐,云原生技术已迅速成为推动创新和实现敏捷性的基石。本文深入探讨了云原生架构的核心组件,包括容器化、微服务、持续集成/持续部署(CI/CD)以及声明式API。通过分析这些技术的协同效应,揭示了它们如何共同促进系统的可伸缩性、弹性和维护性,进而支持企业在不断变化的市场环境中保持竞争力。
10 1
|
5天前
|
敏捷开发 Cloud Native 持续交付
构建未来:云原生架构的进化之路
【4月更文挑战第21天】随着数字化转型的深入,企业对IT基础设施的要求日益提高。云原生技术以其灵活性、可扩展性和敏捷性成为推动创新的重要力量。本文将探讨云原生架构的核心组件,分析其如何助力企业实现快速迭代和高效运营,并预测云原生技术的发展趋势。
|
8天前
|
监控 持续交付 开发者
构建高效微服务架构:后端开发的新趋势
【4月更文挑战第18天】在数字化转型的浪潮中,微服务架构已成为企业提升系统灵活性、加速产品迭代的关键。此文深入探讨了构建高效微服务架构的实践方法,包括服务划分原则、容器化部署、持续集成/持续部署(CI/CD)流程以及监控与日志管理等关键技术点。通过分析具体案例,揭示了微服务在提高开发效率、降低维护成本及促进团队协作方面的显著优势。
|
8天前
|
Cloud Native 持续交付 云计算
构建未来:云原生架构在企业数字化转型中的关键作用
【4月更文挑战第18天】 随着企业加速迈向数字化,云原生架构成为推动创新与效率的催化剂。本文深入探讨了云原生技术如何助力企业实现敏捷开发、自动化运维和无缝可扩展性,以及它如何塑造着云计算的未来。我们将通过具体案例分析,揭示云原生架构在处理复杂系统时的灵活性和可靠性,并展望其对业务连续性和安全性的积极影响。
13 1