每个实例都有一个代理字典有什么缺点?

时间:2018-02-08 23:43:14

标签: c# design-patterns asp.net-core

我正在开发Asp.net Core 2 MVC项目,如下所示。通过删除我们应该熟悉的部分,我将尽可能简化代码片段。

  • 实体模型

    public class Customer
    {
        public string Id { get; set; }
        public string CompanyName { get; set; }
        public string ContactName { get; set; }
        public string Country { get; set; }
    }
    
  • 数据库上下文

    public class AppDbContext : DbContext
    {
        public DbSet<Customer> Customers { get; set; }
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
    }
    
  • 按国家,公司名称和其他人搜索的辅助类

    public class Search
    {
        public enum Options
        {
            [Display(Name="By Country")]
            ByCountry = 1,
            [Display(Name = "By Company Name")]
            ByCompanyName = 2,
            // in the future there will be other items appended   
        }
    
        public AppDbContext Context { get; }
        public IDictionary<Options, Func<string, IEnumerable<Customer>>> SearchMethods { get; }
    
        public Search(AppDbContext context)
        {
            Context = context;
            SearchMethods =
                new Dictionary<Options, Func<string, IEnumerable<Customer>>>()
                {
                    [Options.ByCountry] = x => Context.Customers
                               .Where(c => c.Country.ToLower().Contains(x.ToLower()))
                               .ToList(),
    
                    [Options.ByCompanyName] = x => Context.Customers
                               .Where(c => c.CompanyName.ToLower().Contains(x.ToLower()))
                               .ToList()
    
                    // in the future there will be other items appended 
                };
        }        
    }
    

Search允许我在控制器和视图中避免使用硬编码的文字字符串。以下是示例:

  • 控制器

    public class HomeController : Controller
    {
        public Search S { get; }
        public HomeController(Search s) => S = s;
    
        [HttpPost]
        public IActionResult Search(string criteria, Search.Options searchBy)
            => View(S.SearchMethods[searchBy](criteria));
    
    }
    
  • 查看

    <input name="criteria" />
    <select name="searchBy" asp-items="Html.GetEnumSelectList<Search.Options>()"></select>
    

问题

我意识到逐渐向Options枚举添加新元素并向SearchMethods字典属性添加新项目不会产生版本问题,只要我能确保Options的元素是在数字上保持相同的顺序。

现在我关心的是这种方法是否有任何缺点?例如,关于性能问题,可伸缩性问题,因为每个SearchMethods实例都有一个字典Search的实例。

欢迎任何意见和建议。

修改

这是我迄今为止做出的最后决定。我使用字典将注册转换为使用switch进行查找,如下所示。

    public class Search
    {
        public enum Options
        {
            [Display(Name = "By Country")]
            ByCountry = 1,
            [Display(Name = "By Company Name")]
            ByCompanyName = 2,
            [Display(Name = "By Contact Name")]
            ByContactName = 3
        }

        public AppDbContext Context { get; }
        public Search(AppDbContext context) => Context = context;

        public IEnumerable<Customer> Filter(string criteria, Options options)
        {
            IEnumerable<Customer> customers = Context.Customers;
            string lowCriteria = criteria.ToLower();
            switch (options)
            {
                case Options.ByCountry:
                    customers = customers.Where(c => c.Country.ToLower().Contains(lowCriteria));
                    break;
                case Options.ByCompanyName:
                    customers = customers.Where(c => c.CompanyName.ToLower().Contains(lowCriteria));
                    break;
                case Options.ByContactName:
                    customers = customers.Where(c => c.ContactName.ToLower().Contains(lowCriteria));
                    break;
            }
            return customers.ToList();
        }
    }

1 个答案:

答案 0 :(得分:1)

您可以使用实际方法使整个课程更容易阅读,并允许您直接使用这些查询,例如用于测试:

public class Search
{
    public AppDbContext Context { get; }
    public IDictionary<Options, Func<string, IEnumerable<Customer>>> SearchMethods { get; }

    public Search(AppDbContext context)
    {
        Context = context;
        SearchMethods = new Dictionary<Options, Func<string, IEnumerable<Customer>>>()
        {
            [Options.ByCountry] = GetByCountry,
            [Options.ByCompanyName] = GetByCompanyName,
        };
    }

    public IEnumerable<Customer> GetByCountry (string countryName)
    {
        return Context.Customers
           .Where(c => c.Country.ToLower().Contains(countryName.ToLower()))
           .ToList();
    }

    public IEnumerable<Customer> GetByCompanyName (string companyName)
    {
        return Context.Customers
            .Where(c => c.CompanyName.ToLower().Contains(companyName.ToLower()))
            .ToList()
    }
}

这仍然存在为每个Search实例创建(基本上是常量的)字典的开销,这意味着每个对范围服务的请求。

我们可以通过静态查找来避免这种情况。不幸的是,我们只能对静态方法执行此操作,因此我们必须稍微更改它们以获取数据库上下文。我们在Search实例中添加了一个实用工具方法:

public class Search
{
    private static IDictionary<Options, Func<AppDbContext, string, IEnumerable<Customer>>> _searchMethods { get; }

    public AppDbContext Context { get; }

    static Search()
    {
        _searchMethods = new Dictionary<Options, Func<AppDbContext, string, IEnumerable<Customer>>>()
        {
            [Options.ByCountry] = GetByCountry,
            [Options.ByCompanyName] = GetByCompanyName,
        };
    }

    public Search(AppDbContext context)
    {
        Context = context;
    }

    public IEnumerable<Customer> Get(Options query, string argument)
        => _searchMethods[query](Context, argument);

    public static IEnumerable<Customer> GetByCountry (AppDbContext context, string countryName)
    {
        return context.Customers
           .Where(c => c.Country.ToLower().Contains(countryName.ToLower()))
           .ToList();
    }

    public static IEnumerable<Customer> GetByCompanyName (AppDbContext context, string companyName)
    {
        return context.Customers
            .Where(c => c.CompanyName.ToLower().Contains(companyName.ToLower()))
            .ToList()
    }
}