0

我已经实现了我的存储库类,但我想知道如何将它的方法重构为可以由不同存储库类型扩展的基类。

我首先创建了下面的基础 Repository 类,但不确定每个方法应该有多抽象。另外我应该如何用通用占位符替换模型类型。

在这个例子中,抽象方法只包含方法定义而不包含实现:

public abstract Array sort(Array arr);

谁能建议如何重构泛型的方法?

我从创建基本的抽象 Repository 类开始,但在用泛型类型和泛型参数替换方法时遇到了困难。

下面的示例Delete()是特定于 CustomerModel 的。它应该是通用的,以便更容易地重用该类:

public abstract class BaseRepository
{
    public async Task DeleteCustomer(CustomerModel customer)
    {
        var collection = StartConnection();
        var filter = Builders<CustomerModel>.Filter.Where(x => x.Id == customer.Id);
        var result = await collection.DeleteOneAsync(filter);
        customers.Remove(customer);
    }
}

例如,这是完整的 CustomerRepository 类,其中包含我的远程数据库的 CRUD 操作。这些方法都是特定于 CustomerModel 的,因此很难重用:

public class CustomerRepository : ICustomerRepository
{
    private static List<CustomerModel> customers = new List<CustomerModel>();

    static CustomerRepository()
    {
    }

    private CustomerRepository()
    {

    }

    public static CustomerRepository Instance
    {
        get
        {
            return instance;
        }
    }

    public CustomerModel GetACustomer()
    {
        if (customers == null)
            LoadCustomers();
        return customers.FirstOrDefault();
    }

    public List<CustomerModel> GetCustomers()
    {
        if (customers.Count == 0)
            LoadCustomers();
        return customers;
    }

    public CustomerModel GetCustomerById(ObjectId id)
    {
        if (customers == null)
            LoadCustomers();
        return customers.Where(c => c.Id == id).FirstOrDefault();
    }

    public CustomerModel GetCustomerByEmail(string email)
    {
        if (customers == null)
            LoadCustomers();
        return customers.Where(c => c.Email == email).FirstOrDefault();
    }

    public async Task DeleteCustomer(CustomerModel customer)
    {
        var collection = StartConnection();
        var filter = Builders<CustomerModel>.Filter.Where(x => x.Id == customer.Id);
        var result = await collection.DeleteOneAsync(filter);
        customers.Remove(customer);
    }

    public async Task AddCustomer(CustomerModel customer)
    {
        var collection = StartConnection();
        await collection.InsertOneAsync(customer);
        customers.Add(customer);
    }

    public async Task UpdateCustomer(CustomerModel customer)
    {          
        var collection = StartConnection();
        var filter = Builders<CustomerModel>.Filter.Where(x => x.Id == customer.Id);

        collection.Find(filter).ToString();
        var result = await collection.ReplaceOneAsync(filter, customer, new UpdateOptions { IsUpsert = true });

        var index = customers.FindIndex(a => a.Id == customer.Id);
        customers[index] = customer;
    }

    private void LoadCustomers()
    {
        var collection = StartConnection();

        try
        {
            customers = collection.Find(new BsonDocument()).ToListAsync().GetAwaiter().GetResult();
        }
        catch (MongoException ex)
        {
            //Log exception here:
            MessageBox.Show("A connection error occurred: " + ex.Message, "Connection Exception", MessageBoxButton.OK, MessageBoxImage.Warning);
        }
    }

    private static IMongoCollection<CustomerModel> StartConnection()
    {
        var client = new MongoClient(connectionString);
        var database = client.GetDatabase("orders");
        //Get a handle on the customers collection:
        var collection = database.GetCollection<CustomerModel>("customers");
        return collection;
    }
}
4

1 回答 1

3

Do not make a base class containing entity specific methods. Make base generic from beginning.

public class Repository<T> where T : new()
{
    public async Task<T> GetAsync(object key)
    {}

    public async Task DeleteAsync(T t)
    {}
}

Add any level of abstraction you feel like. If you are using e.g. some kind of ORM within your repo this could be enough.


You can't change the method names in inheriting classes. And it's more straight forward to use repos if all have same methods for operations.

If you can use base as is, then only Type parameter changes. So you'd instantiate e.g. Repository<Customer> in your code.

If logic differs between entities, then have e.g. CustomerRepository : Repository<Customer> and put logic there. Also, mark base as abstract and methods abstract/virtual.

于 2015-12-03T10:39:55.020 回答