Is there a name for this design pattern where a concrete class implements a specific interface which implements a base interface for CRUD operations?

huangapple go评论66阅读模式
英文:

Is there a name for this design pattern where a concrete class implements a specific interface which implements a base interface for CRUD operations?

问题

我曾试图将这个问题变成一个“通用”问题,因为我在Java和C#中都见过类似的情况,并且我认为其他面向对象的语言中也有类似情况。

我知道有三个“主要”框架用于访问数据并执行CRUD操作的应用程序:

  • MVP
  • MVC
  • MVVM

有时这些设计模式会使用DAO,有时会使用DTO。

在查看使用这三种设计模式之一的应用程序的教程和示例时,大多数(如果不是全部)都会做类似这样的事情:

BaseRepositoryInterface(有时我见过它是一个接口,有时见过它是一个抽象类)

interface BaseRepositoryInterface {

    findOne(integer id);

    findAll();

    create();

    read(integer id);

    update(integer id);

    delete(integer id);
}

SpecificRepositoryInterface

interface SpecificRepositoryInterface implements BaseRepositoryInterface {

    // Just Some Examples
    specificActionNumberOne(integer id, String someString);

    specificActionNumberTwo(integer id, Object someObject);

    specificActionNumberThree(integer id, double someDouble);
}

ConcreteRepositoryClass

class ConcreteRepositoryClass implements SpecificRepositoryInterface {

    Dao myDao;
    // or
    Dto myDto;

    ConcreteRepositoryClass(Dao someDao)
    // or 
    ConcreteRepositoryClass(Dto someDto)
    {
        this.myDao = someDao;
        // or
        this.myDto = someDto;
    }

    findOne(integer id){
        // implement here ...
    }

    findAll(){
        // implement here ...
    }

    create(){
        // implement here ...
    }

    read(integer id){
        // implement here ...
    }

    update(integer id){
        // implement here ...
    }

    delete(integer id){
        // implement here ...
    }

    specificActionNumberOne(integer id, String someString){
        // implement here ...
    }

    specificActionNumberTwo(integer id, Object someObject){
        // implement here ...
    }

    specificActionNumberThree(integer id, double someDouble){
        // implement here ...
    }
}

虽然不是所有示例都完全相同,但它们都倾向于遵循相同的格式。

鉴于此,是否有一个名字来表示这种设计模式?

可以肯定地认为,我正在寻找的这种模式是前述框架中的“presenter”、“controller”或“view model”部分,只是进一步抽象化了吗?

英文:

I have tried to make this a "generic" question as I have seen this in Java and C#, and I'm assuming it is in other OO languages as well.

I know there are three "main" frameworks for an application that accesses data and that perform CRUD operations:

Sometimes these design patterns use a DAO and sometimes they use a DTO.

In looking at tutorials and examples of applications that use one of these three design patterns, most, if not all, do something like this:

BaseRepositoryInterface (I have sometimes seen this as an interface and sometimes seen it as an abstract class)

interface BaseRepositoryInterface {

    findOne(integer id);

    findAll();

    create();

    read(integer id);

    update(integer id);

    delete(integer id);
}

SpecificRepositoryInterface

interface SpecificRepositoryInterface implements BaseRepositoryInterface {

    // Just Some Examples
    specificActionNumberOne(integer id, String someString);

    specificActionNumberTwo(integer id, Object someObject);

    specificActionNumberThree(integer id, double someDouble);
}

ConcreteRepositoryClass

class ConcreteRepositoryClass implements SpecificRepositoryInterface {

    Dao myDao;
    // or
    Dto myDto;

    ConcreteRepositoryClass(Dao someDao)
    // or 
    ConcreteRepositoryClass(Dto someDto)
    {
        this.myDao = someDao;
        // or
        this.myDto = someDto;
    }

    findOne(integer id){
        // implement here ...
    }

    findAll(){
        // implement here ...
    }

    create(){
        // implement here ...
    }

    read(integer id){
        // implement here ...
    }

    update(integer id){
        // implement here ...
    }

    delete(integer id){
        // implement here ...
    }

    specificActionNumberOne(integer id, String someString){
        // implement here ...
    }

    specificActionNumberTwo(integer id, Object someObject){
        // implement here ...
    }

    specificActionNumberThree(integer id, double someDouble){
        // implement here ...
    }
}

This is not always exactly the same in all examples, but they all tend to follow the same format.

Given this, is there a name for this design pattern?

Is it safe to assume that this pattern whose name I am looking for is the "presenter", "controller", or "view model" portion of the aforementioned frameworks, just further abstracted?

答案1

得分: 1

这对于我来说就是仓库模式。在大多数情况下,这在模型的背后或与模型相连接。从仓库中,您可以为模型提供所有这些模式中提到的数据。模型可以直接存储在仓库中,或者在转换为某些DTO后存储在仓库中。仓库通常由接口表示,以便在没有与持久层进行实际连接的情况下进行测试。

英文:

For me this is repository pattern. In most cases this is behind model or connected to the model. From repository you can provide data to model for all of this patterns which you mentioned. Model can be store in repository directly or after transformation to some DTO. The repository often is represent by interface to give possibility to test without real connection to persistence layer.

答案2

得分: 0

我们有一个通用的仓储模式(Generic Repository Pattern),也有一个特定的仓储模式(Specific Repository Pattern)。它们都是正确的,各有优缺点。

要在 C# 中实现仓储模式:

public interface ICustomerRepository 
{        
    IEnumerable<Customer> GetCustomers();        
    Customer GetCustomerByID(int customerId);        
    void InsertCustomer(Customer customer);        
    void DeleteCustomer(int customerId);        
    void UpdateCustomer(Customer customer);        
    void Save();    
}

上述接口的 EF 实现如下:

public class CustomerRepository : ICustomerRepository    
{        
    private ApplicationContext context;        
 
    public CustomerRepository(ApplicationContext context)        
    {            
        this.context = context;        
    }        
    
    public IEnumerable<Customer> GetCustomers()        
    {            
        return context.Customers.ToList();        
    }        
    public Customer GetCustomerByID(int customerId)        
    {
        return context.Customers.Find(customerId);
    }
    
    public void InsertCustomer(Customer customer)
    {            
        context.Customers.Add(customer);      
    }        
    
    public void DeleteCustomer(int customerId)        
    {            
        Customer customer = context.Customers.Find(customerId);                    
        context.Customers.Remove(customer);        
    }        
    
    public void UpdateCustomer(Customer customer)        
    {            
        context.Entry(customer).State = EntityState.Modified;        
    }        
    
    public void Save()        
    {            
        context.SaveChanges();        
    }
    
}

现在来实现 C# 中的通用仓储模式:

首先,为通用仓储创建一个接口:

public interface IRepository<TEntity> where TEntity : class
{
    void Delete(TEntity entityToDelete);
    void Delete(object id);
    IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null, 
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, 
        string includeProperties = "");
    TEntity GetByID(object id);
    IEnumerable<TEntity> GetWithRawSql(string query, 
        params object[] parameters);
    void Insert(TEntity entity);
    void Update(TEntity entityToUpdate);
}

然后,使用 EF 实现上述接口,代码如下:

class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    internal ApplicationContext context;
    internal DbSet<TEntity> dbSet;

    public BaseRepository(ApplicationContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> GetWithRawSql(string query, 
        params object[] parameters)
    {
        return dbSet.SqlQuery(query, parameters).ToList();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        if (includeProperties != null)
        {
            foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }
        }
            
        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }

    public virtual void Delete(object id)
    {
        TEntity entityToDelete = dbSet.Find(id);
        Delete(entityToDelete);
    }

    public virtual void Delete(TEntity entityToDelete)
    {
        if (context.Entry(entityToDelete).State == EntityState.Detached)
        {
            dbSet.Attach(entityToDelete);
        }
        dbSet.Remove(entityToDelete);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        dbSet.Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

关于仓储的更多内容(C# 中的 Unit Of Work 模式):

Unit Of Work 模式 C#

为单个事务使用单独的仓储可能会导致部分更新。例如,假设您必须在同一事务的一部分中更新两种不同的实体类型。如果每个实体类型都使用单独的数据库上下文实例,一个可能成功,另一个可能失败。确保所有仓储都使用相同的数据库上下文(从而协调所有更新)的一种方法是使用单元工作(Unit Of Work)类。

public interface IUnitOfWork
{
    IRepository<Customer> Customers { get; }
    IRepository<Order> Orders { get; }
    void Commit();
}

以下是上述 IUnitOfWork 实现的代码:

public class UnitOfWork : IUnitOfWork
{
    private ApplicationContext _dbContext;
    private BaseRepository<Customer> _customers;
    private BaseRepository<Order> _orders;

    public UnitOfWork(ApplicationContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IRepository<Customer> Customers
    {
        get
        {
            return _customers ?? 
                (_customers = new BaseRepository<Customer>(_dbContext));
        }
    }

    public IRepository<Order> Orders
    {
        get
        {
            return _orders ?? 
                (_orders = new BaseRepository<Order>(_dbContext));
        }
    }

    public void Commit()
    {
        _dbContext.SaveChanges();
    }
}
英文:

we have a Generic Repository Pattern and also have a specific Repository Pattern. Both of them are correct and have their pros and cons.

for implement Repository Pattern in C#:

public interface ICustomerRepository 
{        
    IEnumerable GetCustomers();        
    Customer GetCustomerByID(int customerId);        
    void InsertCustomer(Customer customer);        
    void DeleteCustomer(int customerId);        
    void UpdateCustomer(Customer customer);        
    void Save();    
}

And the implementation of the above interface with EF looks like this:

public class CustomerRepository:ICustomerRepository    
{        
    private ApplicationContext context;        
 
    public CustomerRepository(ApplicationContext context)        
    {            
        this.context = context;        
    }        
    
    public IEnumerable&lt;Customer&gt; GetCustomers()        
    {            
        return context.Customers.ToList();        
    }        
    public Customer GetCustomerByID(int customerId)        
    {
        return context.Customers.Find(customerId);
    }
    
    public void InsertCustomer(Customer customer)
    {            
        context.Customers.Add(customer);      
    }        
    
    public void DeleteCustomer(int customerId)        
    {            
        Customer customer = context.Customers.Find(customerId);                    
        context.Customers.Remove(customer);        
    }        
    
    public void UpdateCustomer(Customer customer)        
    {            
        context.Entry(customer).State = EntityState.Modified;        
    }        
    
    public void Save()        
    {            
        context.SaveChanges();        
    }
    
}

That's It!

Now to implement Generic Repository Pattern in C#

first, make an interface for the generic repository

public interface IRepository&lt;TEntity&gt; where TEntity :class
{
    void Delete(TEntity entityToDelete);
    void Delete(object id);
    IEnumerable&lt;TEntity&gt; Get(
        Expression&lt;Func&lt;TEntity, bool&gt;&gt; filter = null, 
        Func&lt;IQueryable&lt;TEntity&gt;, IOrderedQueryable&lt;TEntity&gt;&gt; orderBy = null, 
        string includeProperties = &quot;&quot;);
    TEntity GetByID(object id);
    IEnumerable&lt;TEntity&gt; GetWithRawSql(string query, 
        params object[] parameters);
    void Insert(TEntity entity);
    void Update(TEntity entityToUpdate);
}

And then the implementation of the above interface with EF looks like this:

class BaseRepository&lt;TEntity&gt; : IRepository &lt;TEntity&gt; where TEntity : class
{
    internal ApplicationContext context;
    internal DbSet&lt;TEntity&gt; dbSet;

    public BaseRepository(ApplicationContext context)
    {
        this.context = context;
        this.dbSet = context.Set&lt;TEntity&gt;();
    }

    public virtual IEnumerable&lt;TEntity&gt; GetWithRawSql(string query, 
        params object[] parameters)
    {
        return dbSet.SqlQuery(query, parameters).ToList();
    }

    public virtual IEnumerable&lt;TEntity&gt; Get(
        Expression&lt;Func&lt;TEntity, bool&gt;&gt; filter = null,
        Func&lt;IQueryable&lt;TEntity&gt;, IOrderedQueryable&lt;TEntity&gt;&gt; orderBy = null,
        string includeProperties = &quot;&quot;)
    {
        IQueryable&lt;TEntity&gt; query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        if (includeProperties != null)
        {
            foreach (var includeProperty in includeProperties.Split
            (new char[] { &#39;,&#39; }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }
        }
            

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }

    public virtual void Delete(object id)
    {
        TEntity entityToDelete = dbSet.Find(id);
        Delete(entityToDelete);
    }

    public virtual void Delete(TEntity entityToDelete)
    {
        if (context.Entry(entityToDelete).State == EntityState.Detached)
        {
            dbSet.Attach(entityToDelete);
        }
        dbSet.Remove(entityToDelete);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        dbSet.Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

something more about repository (Unit Of Work Pattern C#):

Unit Of Work Pattern C#

The use of a separate repository for a single transaction could result in partial updates. For example, suppose you have to update two different entity types as part of the same transaction. If each uses a separate database context instance, one might succeed and the other might fail, and one way to ensure that all repositories use the same database context (and thus coordinate all updates) is to use a unit of work class.

public interface IUnitOfWork
{
    IRepository&lt;Customer&gt; Customers { get; }
    IRepository&lt;Order&gt; Orders { get; }
    void Commit();
}

Below is the code of how the implementation of above IUnitOfWork will look like,

public class UnitOfWork : IUnitOfWork
{

    private ApplicationContext _dbContext;
    private BaseRepository&lt;Customer&gt; _customers;
    private BaseRepository&lt;Order&gt; _orders;

    public UnitOfWork(ApplicationContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IRepository&lt;Customer&gt; Customers
    {
        get
        {
            return _customers ?? 
                (_customers=new BaseRepository&lt;Customer&gt;(_dbContext));
        }
    }

    public IRepository&lt;Order&gt; Orders
    {
        get
        {
            return _orders ?? 
                (_orders=new BaseRepository&lt;Order&gt;(_dbContext));
        }
    }

    public void Commit()
    {
        _dbContext.SaveChanges();
    }
}

huangapple
  • 本文由 发表于 2020年10月13日 03:07:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/64323934.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定