【问题标题】:How to refactor method into generic base class implementation?如何将方法重构为通用基类实现?
【发布时间】:2016-03-07 22:17:33
【问题描述】:

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

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

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

public abstract Array sort(Array arr);

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

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

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

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

【问题讨论】:

    标签: c# refactoring abstract-class base-class generic-method


    【解决方案1】:

    不要创建包含实体特定方法的基类。 从一开始就使基础通用。

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

    添加您喜欢的任何抽象级别。如果您正在使用例如您的仓库中的某种 ORM 就足够了。


    您不能更改继承类中的方法名称。如果所有的操作方法都相同,那么使用 repos 会更直接。

    如果您可以按原样使用 base,那么只有 Type 参数会发生变化。所以你会实例化例如Repository&lt;Customer&gt; 在您的代码中。

    如果实体之间的逻辑不同,则具有例如CustomerRepository : Repository&lt;Customer&gt; 并将逻辑放在那里。此外,将基础标记为抽象,将方法标记为抽象/虚拟。

    【讨论】:

    • 该类应该标记为抽象类吗?另外,当我扩展类时,是否可以将继承的方法名称更改为键入特定实例?
    • 我决定实现 IRepository 接口而不是类,因为它使单元测试更容易。以上信息有助于重构,此链接blog.falafel.com/…
    • 对于单元测试,您可以使用Moq,您可以通过 NuGet 获得。它允许您模拟和连接您的存储库。
    猜你喜欢
    • 2021-06-08
    • 2021-07-16
    • 1970-01-01
    • 2021-05-24
    • 2017-06-07
    • 2012-09-10
    • 2021-10-21
    • 2014-12-02
    • 2015-03-20
    相关资源
    最近更新 更多