Шаблон проектирования для вывода отдельных файлов из одного входного параметра

1

У меня есть этот класс продуктов с 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();
            }
    }

Мне кажется, что я пишу один и тот же код три раза (с небольшими вариациями). Я начал читать различные шаблоны дизайна, такие как шаблон Visitor и Strategy, но я не уверен, какой шаблон дизайна улучшил мой код. (Примечание: мне нужно только вывести его в файл с разделителями-запятыми в это время. Кроме того, с пользовательского интерфейса пользователь выбирает, какой из них хочет вывести (один из всех трех файлов). Любые предложения?

Теги:
design-patterns

2 ответа

1
Лучший ответ

Я бы убрал ответственность за форматирование из вашего FoodService и вместо этого 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);
    }

Это позволяет создавать конкретные форматирующие ElligableFoodsFormatter такие как CalculationFormatter и ElligableFoodsFormatter.

  • 0
    Спасибо венерик! Мне тоже нравится эта идея.
  • 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);
  • 0
    Спасибо, Джон! Я ценю ваши отзывы и пример!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню