我该如何重构这段代码?

时间:2011-01-03 21:36:45

标签: c# asp.net linq generics refactoring

我有.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;

3 个答案:

答案 0 :(得分:5)

假设有两件事:

  1. MeatCheese继承自Ingredient或实施IIngredient
  2. MeatsCheeses个集合为IList<T>
  3. 我们走了:

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

答案 1 :(得分:3)

初看起来,您可以访问一些常用属性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,以及您引用Meat或{{1你只需要引用Cheese

了解你能走多远,并进一步重构。

答案 2 :(得分:1)

在不知道所使用的类型(和基本类型/接口)的情况下,很难知道您的确切要求。我假设你正在使用某种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<Cheese>(product);

接下来的部分,我需要假设您的奶酪和肉类对象(或属性),也共享一个公共类(ICollection<IProduct>),或者您可以根据特定需要定义自己的。

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的想法持怀疑态度。修改集合可能会导致用于循环遍历它的枚举器出现问题。如果这是一个问题,我会找到一个更好的方法。