简体   繁体   中英

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

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?

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.

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<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();        
    }
    
}

That's It!

Now to implement Generic Repository Pattern in C#

first, make an interface for the generic repository

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);
}

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

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;
    }
}

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<Customer> Customers { get; }
    IRepository<Order> 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<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();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM