Про использование функционального стиля в ежедневном C#. Убираем простое дублирование кода

30 декабря 2009 г.

Современное ПО для создания другого ПО достигло огромных высот. Хоть и похоже на тавтологию но это правда. После появления Java и IntelijIdea а так же C# нам как программистам очень мало рутинной работы осталось делать руками. Даже рефакторинги оказались автоматизированными. Казалось — бы программисту осталось только напрягать голову для создания прекрасных дизайнов и алгоритмов. Имхо осталась одна проблема идущая с незапамятных времен и до сих пор не решенная в мейнстриме и языками программирования и средами разработки. Эта проблема — дублирование кода. Вот тут нам и помогает фп.

Сразу оговорюсь что я буду описывать именно C# хотя наверное идеи можно перетащить и в другой яп.
Траи и кетчи, а также юзинги и другие локи.
Очень часто мне встречается подобный код

void ReadSomeImpotantDataFromXml()
{
  lock(fileName)
  {
    using(XmlReader reader = XmlReader.Create(fileName))
    {
      while(reader.Read())
      {
        try
        {
          //do some stuff 1
        }
        catch(InvalidReadException ex)
        {
          //do dome stuff 2
        }
      }
    }
  }
}

вполне нормально быстрое и потоко — безопасное чтение из xml. Кода оно одно — нет проблем и все хорошо, но вот если его надо использовать в нескольких местах с разной логикой обработки в do some stuff 1 и do some stuff 2 вот тут и начинаются проблемы. Кож естественно расплывается по проекту (по нескольким?). И вот тут выходит класс который позволяет нам читать Xml в 2раза быстрее чем XmlReader. Вы четко понимаете что надо перезжать. Вот только как? Искать эти фрагменты во всех проектах — уму не постижимо. Что же делать? Давайте устроим маленький рефакторинг :)

Action<Action,Action> initFunction = (doSomeStuff1,doSomeStuff2,fileName)=>
                    {
                      lock(fileName)
                      {
                        using(XmlReader reader = XmlReader.Create(fileName))
                        {
                          while(reader.Read())
                          {
                            try
                            {
                              doSomeStuff1(reader);
                            }
                            catch(InvalidReadException ex)
                            {
                              doSomeStuff2(ex);
                            }
                          }
                        }
                      }
                    };
void ReadSomeImpotantDataFromXml()
{
  initFunction(reader=>
        {
          //do some stuff 1
        },
        ex=>
        {
          //do some stuff 2
        },
        fileName);
}

В общем-то теперь мы можем использовать initFunction где угодно и при изменение XmlReader на XmlReader2 сделать нам это придется только в 1м месте.
Предыдущий пример показал идею известную давно, но практически его применить очень трудно. Не везде процесс инициализации и освобождения ресурсов так прост. Точнее он нигде не бывает так прост и так одинаков.

Теги:
рубрика C#