我有这个Food类有20个属性。我需要使用这个Food类并输出3个不同的文件,使用这20个字段的变体。例如,文件1仅包含8个字段。文件2包含15个字段。文件3包含18个字段。
所以现在,我有这三种不同的方法。
FoodService()
{
void WriteRecommendedFood(IList<Food> foodList);
void WriteRecommendedFoodCalculation(IList<Food> foodList);
void WriteRecommendedFoodAllEligibleFoods(IList<Food> foodList);
}
所以我写道:
public void WriteRecommendedFood(IList<Food> foodList)
{
using (StreamWriter sw = new StreamWriter("file.csv", false)
{
StringBuilder sb = new StringBuilder();
foreach (Food f in foodList)
{
sb.Append(f.Field1);
//Repeat for the # of fields I want to spit out
sb.Clear();
sw.WriteLIne(sb.ToString());
}
sw.Close();
}
}
我觉得我正在写三次相同的代码(略有不同)。 我开始阅读不同的设计模式,如访问者和策略模式,但我不确定改进我的代码的设计模式。 (注意:此时我只需要将其输出到逗号分隔文件。此外,从UI端,用户可以选择要输出哪一个(所有3个文件中的一个。)任何建议?
答案 0 :(得分:2)
似乎这三个函数之间唯一的变化是写入的字段列表。有几种方法可以表示程序中的“字段”(以及字段列表);其中一个最方便的功能就是从Food
实例中提取该字段的值。
此表示的类型为Func<Food, object>
,因此使用List<Func<Food, object>>
您就可以了。
public void WriteFoodData(IEnumerable<Food> foodList, IEnumerable<Func<Food, object>> valueProviders)
{
using (StreamWriter sw = new StreamWriter("file.csv", false))
{
StringBuilder sb = new StringBuilder();
foreach (Food f in foodList)
{
foreach (var provider in valueProviders)
{
sb.Append(provider(f).ToString());
}
sw.WriteLIne(sb.ToString());
sb.Clear();
}
}
}
现在您可以创建“字段列表”并使用它来调用此方法:
var valueProviders = new List<Func<Food, object>>
{
f => f.Field1,
f => f.Field4,
// etc
};
var foods = /* whatever */
WriteFoodData(foods, valueProviders);
答案 1 :(得分:1)
我会从FoodService
中删除格式化的责任并将其注入。
public class FoodService()
{
public void WriteRecommendedFood(IList<Food> foodList, IFoodFormatter formatter)
{
using (StreamWriter sw = new StreamWriter("file.csv", false)
{
StringBuilder sb = new StringBuilder();
foreach (Food f in foodList)
{
sw.WriteLine(foodformatter.Format(f));
}
sw.Close();
}
}
}
interface IFoodFormatter
{
string Format(Food f);
}
您可以创建具体的格式化程序,例如CalculationFormatter
和ElligableFoodsFormatter
。