【问题标题】:how do i refactor this code?我如何重构这段代码?
【发布时间】:2011-01-03 21:36:44
【问题描述】:

我有 .net 3.5,我想做一个通用方法。如何重构这段代码?

            case (int)Enums.SandwichesHoagies.Cheeses:
                if (this.Cheeses.Where(x => x.Id == product.ProductId).SingleOrDefault() == null)
                {
                    var newCheese = new Cheese
                    {
                        Id = product.ProductId,
                        Name = product.Name,
                        PriceValue = product.Price.HasValue ? (double)product.Price.Value : 0.00
                    };

                    this.Cheeses.Add(newCheese);
                }
                else
                {
                    foreach (var cheese in this.Cheeses.Where(cheese => cheese.Id == product.ProductId))
                    {
                        this.Cheeses.Remove(cheese);
                        break;
                    }
                }

                foreach (var cheese in Cheeses) cheese.Type = string.Empty;

                if (this.Cheeses.Count > 0) Cheeses.First().Type = "Cheeses:";

                break;

            case (int)Enums.SandwichesHoagies.Meats:
                if (this.Meats.Where(x => x.Id == product.ProductId).SingleOrDefault() == null)
                {
                    var newMeat = new Meat
                    {
                        Id = product.ProductId,
                        Name = product.Name,
                        PriceValue = product.Price.HasValue ? (double)product.Price.Value : 0.00
                    };

                    this.Meats.Add(newMeat);
                }
                else
                {
                    foreach (var meat in this.Meats.Where(meat => meat.Id == product.ProductId))
                    {
                        this.Meats.Remove(meat);
                        break;
                    }
                }

                foreach (var meat in Meats) meat.Type = string.Empty;

                if (this.Meats.Count > 0) Meats.First().Type = "Meats:";

                break;

【问题讨论】:

  • 我非常想处理这些数据。 SandwichesHoagies.Meats!

标签: c# asp.net linq generics refactoring


【解决方案1】:

假设两件事:

  1. MeatCheese 继承自 Ingredient 或实现 IIngredient
  2. MeatsCheeses 集合是 IList<T>

我们开始吧:

private void OuterMethod()
{
   switch(something)
   {
       case (int)Enums.SandwichesHoagies.Cheeses:
           HandleCase(product, this.Cheeses);
           break;
       case (int)Enums.SandwichesHoagies.Meats:
           HandleCase(product, this.Meats);
           break;
   }
}

private void HandleCase<T>(Product product, List<T> list) where T : Ingredient, new()
{
    if(list.Any(i => i.Id == product.ProductId))
    {
        list.Add(new T {
            Id = product.ProductId,
            Name = product.Name,
            PriceValue = product.PriceValue ?? 0.0;
        });
    }
    else
    {
        list.RemoveAll(i => i.Id == product.ProductId);
    }

    //NOTE: this part seems like a bad idea. looks like code smell.
    foreach (var i in list)
    {
        i.Type = string.Empty;
    }
    if (list.Count > 0)
    {
        list.First().Type = "Cheeses:";
    }
}

【讨论】:

  • 如果 Meat 和 Cheese 是生成的类,例如来自EF,您可以在部分类中添加IIngredient,即public partial class Meat : IIngredient {}
【解决方案2】:

乍一看,您可以访问一些常见的属性,Id, Name, PriceValue, and Type。对我来说,这看起来像是一个基类或接口。有了它,您可以首先将代码重构为方法

void YourMethod<T>(List<T> list, Product product) where T : IProduct, new() 
// IProduct being your interface or base class

在这种情况下,当您引用 this.Meatsthis.Cheeses 时,您将改为引用 list,而在您引用 MeatCheese 的实例时,您只需引用 T .

看看这能让你走多远并进一步重构。

【讨论】:

    【解决方案3】:

    如果不知道使用的类型(和基本类型/接口),很难知道您的确切要求。我将假设您正在使用某种 ORM 无论如何都会吐出部分类。

    要使其易于使用的第一个要求是 Meat 和 Cheese 共享一个公共接口(或抽象类)。这应该是这样的基本内容。

    interface IProduct {
        int Id { get; set; }
        String Name { get; set; }
        Double PriceValue { get; set; }
    }
    

    使用部分类的假设使得扩展您的类以使用此接口变得容易。

    partial class Cheese : IProduct { }
    

    我发现有趣的是,您有一种不同类型的产品,它具有不同的字段名称,但功能几乎相同。您是否应该保持名称与上述接口相同并使其也从接口派生?无论如何,假设您拥有的是这样的东西。

    class Product {
        int ProductId { get; set; }
        String Name { get; set; }
        Price? Price { get; set; }
    }
    

    您要做的第一件事是使用工厂模式来创建特定产品。

    public class ProductFactory {
        public T Create<T>(Product product) 
          where T : IProduct, new() {
            return new T {
                Id = product.ProductId,
                Name = product.Name,
                PriceValue = product.Price.HasValue 
                    ? (double)product.Price.Value 
                    : 0.00    
            };
        }
    }
    

    new() 约束需要 Cheese 和 Meat 类中的无参数构造函数。我认为这没有问题。您只需拨打.Create&lt;Cheese&gt;(product);

    接下来的部分,我需要假设您的 Cheeses 和 Meats 对象(或属性)也共享一个公共类 (ICollection&lt;IProduct&gt;),或者您可以根据特定需求定义自己的类。

    public class ProductCollection : ICollection<IProduct> { ... }
    

    检查产品是否存在的通用方法

    Boolean ContainsProduct<T>(ProductCollection<T> collection, Product product) 
      where T : IProduct {
        return collection.Where(x => x.Id == product.Id).SingleOrDefault != null;
    }
    

    我对您在 foreach 循环中调用 .Remove 的想法持怀疑态度。修改集合可能会导致用于循环遍历它的枚举器出现问题。如果这是一个问题,我会找到更好的方法。

    【讨论】:

    • .Remove:有一个 List.RemoveAll&lt;&gt; 方法可以做到这一点,即如果 ProductCollection 是一个列表,它就变成了简单的 collection.RemoveAll(x =&gt; x.Id == product.Id);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多