• 【Yom框架】漫谈个人框架的设计之一:是IRepository还是IRepository<T>?


    前言                                                                                                                 

    对于仓储Repository的设计,其实很多人都很纠结,因为从广义来说,Repository有两种类型:

    IRepositoryIRepository<T>

    框架的重构想得最多的最重要的几个问题:

    1:解耦(每层可以替换其他的,比如换一个UI层可以把Web 项目快速转换成Winform项目)

    2:扩展性(可以灵活抹去框架的某个层,让其他的第三方框架依据自己的接口实现该层的逻辑,其它层不变,也就是插拔式扩展)

    3:灵活(开发便捷,使用灵活)

    4:维护性(别人了解框架后,可以让别人无障碍维护)

    ........

    -------------------------------------

    题外话不多说 马上进入辩证主题:是IRepository还是IRepository<T>

    ------------------------------------

    首先看IRepository<T>                                                                   

    IRepository<T>接口定义形式如下(其中IEntity是一个实体类接口):

     1 public interface IRepository<T> where T : Entity.IEntity
     2     {
     3         T FindBy(string primaryKey);
     4         IEnumerable<T> FindAll();
     5         IEnumerable<T> FindAll(string where);
     6         IEnumerable<T> FindAll(string where, string order);
     7         IEnumerable<T> FindAll(int pageIndex, int pageSize, string where, string order, out int count);
     8         void Add(T entity);
     9         void Delete(T entity);
    10         void DeleteAll();
    11         void DeleteAll(string where);
    12         void DeleteAll(System.Collections.IEnumerable pkValues);
    13         void Update(T entity);
    14         bool Exists(string primaryKey);
    15     }

    可以看见,IRepository和接口IEntity通过泛型T结合在了一起,形成了耦合

    IRepository<T> 可以通过T操作IEntity

    开发的时候,每个IEntity的子类都得对应一个IRepository<T>的子类,如:

    public class DepartmentRepository :  Repository.RepositoryBase<Entity.Department.Department>
        {
        }

    其中Department是IEntity的一个子类

    而RepositoryBase<T>是一个真正可用的仓储父类(此类已通过第三方或者自己的ORM框架实现了数据库操作)

    ------------------------------------

    再看IRepository接口                                                                                

    ------------------------------------

    IRepository接口的设计:

    public interface IRepository
        {
            #region 实体相关接口 
            TEntity FindBy<TEntity>(IEnumerable<string> primaryKey)
                where TEntity : IEntity;
    
            IEnumerable<TEntity> FindAll<TEntity>() where TEntity : IEntity;
    
            IEnumerable<TEntity> FindAll<TEntity>(string where, params System.Data.IDataParameter[] ps) where TEntity : IEntity;
    
            IEnumerable<TEntity> FindAll<TEntity>(string where, string order, params System.Data.IDataParameter[] ps) where TEntity : IEntity;
    
            IEnumerable<TEntity> FindAll<TEntity>(int pageIndex, int pageSize, string where, string order, out int count, params System.Data.IDataParameter[] ps) where TEntity : IEntity;
    
            void Add<TEntity>(TEntity entity) where TEntity : IEntity;
    
            void Delete<TEntity>(TEntity entity) where TEntity : IEntity;
    
            void DeleteAll<TEntity>() where TEntity : IEntity;
    
            void DeleteAll<TEntity>(string where, params System.Data.IDataParameter[] ps) where TEntity : IEntity;
    
            void DeleteAll<TEntity>(IEnumerable<IEnumerable<string>> pkValues)
                where TEntity : IEntity;
    
            void Update<TEntity>(TEntity entity) where TEntity : IEntity;
    
            bool Exists<TEntity>(IEnumerable<string> primaryKey)
                where TEntity : IEntity;
    
            #endregion
            #region 原始数据操作接口
    
            int ExecuteSql(string sql, params System.Data.IDataParameter[] ps);
    
            object ExecuteScalar(string sql, params System.Data.IDataParameter[] ps);
    
            System.Data.DataTable ExecuteDataTable(string sql, params System.Data.IDataParameter[] ps);
            #endregion
        }

    这种接口的设计就是把IReopository<T>里的T放入接口的方法中,

    让泛型方法操作对应的带入泛型实体类

    IReopository接口的设计可以很好地实现Repository共用

    也就是说整个项目只要一个通过ORM实现了的RepositoryBase类就可以操作所有的持久层实体对象

    不用每个实体类都对应一个Repository

    大大的减少了项目开发的繁杂性

    对于业务逻辑,新增一个Server层让每个Server类对应一个实体类的逻辑

    如:假设有Class Aa 则必须有 Class AaServer对应

    而Server就调用RepositoryBase类操作Server类对应的实体

    --------------------------------------

    总结:                                                                                                                     

    其实不管是IRepository还是IRepository<T> 都各自有各自的优势:

    1、IRepository<T>的子类对实体类是很专注的,它只可以操作一个实体类,对IRepository<T>的子类的修改不会影响到其他实体类的操作

    从而可以实现对应实体类的个性化拓展;

    2、IRepository可以操作所有的实体类,修改IRepository的子类则会影响所有的实体的操作

    虽然如此,在开发过程中,难免会有在某个业务层XxServer操作其他实体类的需要

    如果是用IRepository<T>仓储,那么必须在业务层XxServer中New很多其他实体类对应的IRepository<T>的子类对象出来

    这对于Repository与Server的解耦是个大忌,也就是说Repository层和Server层已经高度耦合了。

    也正因为这个原因我个人更倾向于IRepository,并抛弃Repository层(如果是每个实体对应一个Repository,那么将需要一个Repository层),

    只让一个可以操作所有所有实体的Repository存在就可以了

    更重要的原因是Repository层相对来说,接口比较稳定,一般的项目,没有要扩展IRepository接口操作的需要。

     所以IRepository接口一个重要的优势是:

    在某个实体类的Server层可以统一用IRepository类的方法实现业务,

    不需要像IRepository<T>实现方式一样,New额外的对象就才可以操作其他实体类,

    只要在【Repository.方法<T>】里的T换成其他实体类就可以了

    这对解耦来说是有好处的。

    所以正是因为这个原因,我选择IRepository,而不是IRepository<T>

    ---------------------

    题外话                                                                                                   

    上面的IRepository接口已经被我再次抛弃了

    抛弃原因如下:

    1:接口的组合主键扩展性差,也就是说主键会受制于ORM框架的实现

    2:不支持搜索和排序解耦

    至于新的IRepository接口 将在下篇文章给出

    -------------------------------------

  • 相关阅读:
    章节十六、3-TestNG方法和类注解
    章节十六、2-TestNG注解和断言
    章节十六、1-TestNG简介
    章节十五、9-自定义Loggers
    章节十五、8-配置文件File Logging
    章节十五、7- 配置文件-Console Logging
    章节十五、6-log4 2-用默认的配置
    章节十五、5-记录日志---Log4j
    章节十五、4-找到当前页所有连接
    030.[转] sql事务特性
  • 原文地址:https://www.cnblogs.com/yomho/p/3296759.html
Copyright © 2020-2023  润新知