如何实现接口并将不同的规则应用于conrete类的实例化

本文关键字:规则 应用于 conrete 实例化 何实现 实现 接口 | 更新日期: 2023-09-27 18:29:04

给定这个类和接口:

public class Property
{
    public string Address { get; set; }
    public string AgencyCode { get; set; }
    public string Name { get; set; }
    public decimal Latitude { get; set; }
    public decimal Longitude { get; set; }
}
public interface IPropertyMatcher
{
    bool IsMatch(Property agencyProperty, Property databaseProperty);
}

假设AgencyCode有三种可能的变体,它们都有不同的匹配规则:

  • Agency1:在.Name.Address上匹配
  • Agency2:在.Latitude.Longitude上匹配
  • Agency3:与.Name匹配(反向)

如何实现IPropertyMatcher接口以确定agencyProperty是否与databaseProperty匹配,并根据agencyProperty.AgencyCode属性中传递的值应用这些不同的规则来确定匹配?

如何实现接口并将不同的规则应用于conrete类的实例化

首先必须创建一个实现接口的类。然后根据类型定义IsMatch方法:

public class Agent1Evaluator : IPropertyMatcher
{
    public bool IsMatch(Property agencyProperty, Property databaseProperty)
    {
        return agencyProperty.Name == databaseProperty.Name && agencyProperty.Address == databaseProperty.Address;
    }
}

我相信你能算出剩下的两个。

或者类似的东西:

const string Agent1 = "Agent1";
public class AgentEvaluator : IPropertyMatcher
{
    public bool IsMatch(Property agencyProperty, Property databaseProperty)
    {
        switch (agencyProperty.AgentType)
        {
            case Agent1:
                return agencyProperty.Name == databaseProperty.Name && agencyProperty.Address == databaseProperty.Address;
            case Agent2:
                ...
        }
    }
}

(您也可以将此方法添加为Property上的static方法)

您可以尝试复合模式:

public class CompositePropertyMatcher : IPropertyMatcher
{
    private readonly IEnumerable<IPropertyMatcher> matchers;
    public CompositePropertyMatcher(IEnumerable<IPropertyMatcher> matchers)
    {
        this.matchers = matchers;
    }
    public bool IsMatch(Property agencyProperty, Property databaseProperty)
    {
        return this.matchers.Any(m => m.IsMatch(agencyProperty, databaseProperty));
    }
}
public class PropertyMatcher1 : IPropertyMatcher
{
    public bool IsMatch(Property agencyProperty, Property databaseProperty)
    {
        return agencyProperty.Name == databaseProperty.Name
            && agencyProperty.Address == databaseProperty.Address;
    }
}
public class PropertyMatcher2 : IPropertyMatcher
{
    public bool IsMatch(Property agencyProperty, Property databaseProperty)
    {
        return agencyProperty.Longitude == databaseProperty.Longitude
            && agencyProperty.Latitude == databaseProperty.Latitude;
    }
}

添加DI库应该不需要注册新的实现。

以下是SimpleInjector 的示例

[Fact]
public void Container_CompositePropertyManager_CallsAllMatchers()
{
    var container = new Container();
    container.RegisterAll<IPropertyMatcher>(this.GetPropertyMatchers());
    container.Register<IPropertyMatcher, CompositePropertyMatcher>();
    var composite = container.GetInstance<IPropertyMatcher>();
    Assert.True(composite.IsMatch(
        new Property { Name = "a", Address = "b", Latitude = 1m, Longitude = 2m },
        new Property { Name = "a", Address = "b", Latitude = 3m, Longitude = 4m }));
    Assert.True(composite.IsMatch(
        new Property { Name = "a", Address = "b", Longitude = 1m, Latitude = 2m },
        new Property { Name = "c", Address = "d", Longitude = 1m, Latitude = 2m }));
    Assert.False(composite.IsMatch(
        new Property { Name = "a", Address = "b", Longitude = 1m, Latitude = 2m },
        new Property { Name = "c", Address = "d", Longitude = 3m, Latitude = 4m }));
}
private IEnumerable<Type> GetPropertyMatchers()
{
    var result =
        from type in typeof(IPropertyMatcher).Assembly.GetTypes()
        where !type.IsAbstract
        where typeof(IPropertyMatcher).IsAssignableFrom(type)
        where type != typeof(CompositePropertyMatcher)
        select type;
    return result;
}

使用此技术,您可以在不更改任何现有代码的情况下添加新的模式匹配器。