如何避免嵌套的开关结构?

时间:2016-01-20 16:24:22

标签: c# .net oop dynamic repository-pattern

例如,我有两个班级

 public class A
 {
     public Guid Id { get; set;}
     public string Type { get; set; }
     public string State { get; set; }
     public string SomeProperty { get; set; }
 }

 public class B 
 {
     public Guid Id { get; set; }
     public string Type { get; set; }
     public string State { get; set; }
     public string AnotherProperty { get; set; }
 }

每个类都有自己的存储库

 public class RepA
 {
     public void Add(A entity)
     {
         // some specific logic here
     }

     public void Delete(A entity)
     {
         // some specific logic here
     }
 }

 public class RepB
 {
     public void Add(B entity)
     {
         // some specific logic here
     }

     public void Delete(B entity)
     {
         // some specific logic here
     }
 }

我需要实现一种方法来保存具有动态类型的实体列表。我想避免使用嵌套的“switch”结构(如下所列),因为我有2种以上的类型和2种以上的状态,代码看起来很乱。

 private readonly RepA _repA = new RepA();
 private readonly RepB _repB = new RepB();

 public void SaveChanges(List<dynamic> entities)
 {
      foreach (var entity in entities)
      {
           switch (entity.Type)
           {
                case "A": 
                     var a = entity as A;
                     switch (entity.State)
                     {
                          case "Added":
                               _repA.Add(a);
                               break;
                          case "Deleted":
                               _repA.Delete(a);
                               break;
                     }
                     break;
                 case "B":
                     var b = entity as B;
                     switch (entity.State)
                     {
                          case "Added":
                               _repB.Add(b);
                               break;
                          case "Deleted":
                               _repB.Delete(b);
                               break;
                     }
                     break;
          }
      }
 }

您能否提出其他解决方案? 我想过基类和基础库的接口。但在这种情况下,何时以及如何初始化_repo,这取决于实体类型?

 private IBaseRep _repo;

 public void SaveChanges(List<dynamic> entities)
 {
      foreach (var entity in entities)
      {
           switch (entity.State)
           {
               case "Added":
                   _repo.Add(entity)
                   break;
               case "Deleted":
                   _repo.Delete(entity)
                   break;
           }
      }
 }

2 个答案:

答案 0 :(得分:1)

visitor pattern专门用于处理同类列表。

答案 1 :(得分:0)

您的实体类AB正在违反DRY原则。下面怎么样?我能想到的一个问题是实体集合的多个枚举,但我不确定你的集合有多大,以确定这是否真的是一个问题。

public abstract class Entity
{
    public Guid Id { get; set; }
    public string Type { get; set; }
    public string State { get; set; }
}

public class A : Entity
{
    public string SomeProperty { get; set; }
}

public class B : Entity
{
    public string AnotherProperty { get; set; }
}

public abstract class Rep<T> where T : Entity
{
    public abstract void Add(T entity);
    public abstract void Delete(T entity);
    public virtual void SaveChanges(IEnumerable<T> entities)
    {
        foreach (var entity in entities)
        {
            switch (entity.State)
            {
                case "Added":
                    Add(entity);
                    break;
                case "Deleted":
                    Delete(entity);
                    break;
                default:
                    throw new InvalidOperationException($"Invalid entity state {entity.State}");
            }
        }
    }
}

public class RepA : Rep<A>
{
    public override void Add(A entity)
    {
        // some specific logic here
    }

    public override void Delete(A entity)
    {
        // some specific logic here
    }
}

public class RepB : Rep<B>
{
    public override void Add(B entity)
    {
        // some specific logic here
    }

    public override void Delete(B entity)
    {
        // some specific logic here
    }
}

public class Program
{
    private static readonly RepA _repA = new RepA();
    private static readonly RepB _repB = new RepB();

    public static void Main()
    {
        var entities = new List<Entity>();

        // fill the list here

        _repA.SaveChanges(entities.OfType<A>());
        _repB.SaveChanges(entities.OfType<B>());
    }
}