Главная » C# » Написание функционального кода на языке С#

0

Язык С# в основном является императивным языком программирования, что ознает, что он главным образом работает с изменениями состояния. Но в С# 3.0 нинает проявляться и функциональный аспект. Целью функционального програирования является создание кода, не вызывающего побочных эффектов. Многие из предыдущих глав содержали аспекты функционального программирования, не называя их явно таковыми. В этой главе рассматривается исключительно предмет функционального программирования.

В главах 9 а 11 были рассмотрены обобщения .NET и лямбда-выражения в контете С#. Мы научились использовать эти возможности для решения проблем обктно-ориентированным способом. В этой главе мы рассмотрим, как использовать эти возможности для решения проблем в контексте функционального программования. (Если вам нужно освежить ваши знания обобщений .NET и лямбдыражений, то повторите материал в главах 9 и 11, прежде чем продолжать с изением этой главы.)

Зачем использовать функциональное программирование?

Возможно, вам приходилось слышать мнение, что функциональное программирание является сложным предметом. Я думаю, что функциональное программирание — не более сложный предмет, чем, скажем, программирование потоков или разработка и реализация компонентов. Но  функциональное программирование представляет собой другой стиль программирования. Ситуация с функциональным программированием  подобна  ситуации,  когда  программист  впервые  сталкивается с объектно-ориентированным кодом. Этот предмет также сначала кажется слоым, т. к. в нем вводятся новые понятия.

Для первого знакомства с функциональным программированием я рекомендую просмотреть видеоинтервью, в котором Андерс Хайлсберг (Anders Hejlsberg) оуждает LINQ и функциональное программирование. Андерс является создателем Delphi и С# (для дополнительной информации см. Web-сайт http://en.wikipedia.org/ wiki/Anders_Hejlsberg). Впечатление о функциональном программировании, которое

я получил от этого интервью,  можно выразить одной строчкой: "Написание кода, не имеющего побочных эффектов".

Написание кода, не имеющего побочных эффектов, является функциональным программ ированием.

Программирование, при котором код имеет побочные эффекты, является империвным программированием. Язык С# является языком императивного програирования. Императивное программирование означает написание кода, который модифицирует состояние. Примером императивного программирования может служить следующий фрагмент кода:

int х = 0; х = х + 1;

Данный код объявляет переменную х, после чего добавляет 1 к значению этой переменной, таким образом, выполняя операции, модифицирующие состояние. Конечно же, это кажется слишком очевидным; в конце концов, для решения прлемы необходимо модифицировать состояние.

Теперь посмотрим на пример побочных эффектов, создаваемых императивным программированием:

class SomeObject { public int Value;

}

class AnotherObjectThatEmbedsSomeObject { SomeObject _child;

public AnotherObjectThatEmbedsSomeObject(SomeObject child) {

_child = child;

}

void MyMethodO {

_Child.Value = 10;

}

}

Допустим, у нас есть следующий метод:

void SomeMethod(AnotherObjectThatEmbedsSomeObject obj) { obj.MyMethod();

}

В данном случае вызов метода MyMethodO создает побочный эффект изменения значения SomeObject .value на 10. В главе б были продемонстрированы высокие качества такого типа кода, т. к. он скрывает информацию и позволяет типу AnotherObjectThatEmbedsSomeObject фокусироваться  на манипулировании  объек-

том someobject без помех. Но эти высокие качества являются палкой о двух коах, т. к. они вызывают побочные эффекты, о которых код, вызывающий метод someMethod (), ничего не знает. (Конечно же, можно спорить, что нужно было сдать, чтобы объект AnotherObjectThatEmbedsSomeObject ЗНЭЛ О потоках, НО целью данного примера было проиллюстрировать побочные эффекты.)

Теоретически, компонентно-ориентированный подход позволяет создание инфртруктуры, которую можно применять для решения нескольких проблем. Скажем, что вы собираетесь покрасить дом. Один из вариантов выполнения этой задачи — установить леса вокруг дома. Это будет более безопасным способом, но рабочие будут вынуждены следить за другими рабочими. Кроме этого, установка и  снос лесов занимает довольно значительное время. Леса можно сравнить с императиым подходом, где нам нужно принимать во внимание многие обстоятельства, включая параллельное исполнение.

Альтернативой лесам при покраске дома будет использование лестницы каждым маляром. Лестницы намного быстрее установить и убрать, чем леса, и они позвяют каждому маляру работать независимо от других (по крайней мере, на своей лестнице). Но недостатком использования лестниц является необходимость перещать  их  на  новый  участок,  уделять  внимание  установке  их должным  образом и в то же самое время не упускать из виду главную задачу покраски дома. Исполование лестниц будет аналогично функциональному подходу.

В то время как написание кода, не имеющего побочных эффектов, является воожным,  это  напрямую  конфликтует  с  императивным  программированием.  Код, в котором не допускается никаких побочных эффектов, должен сохранять все даые в стеке, что не всегда возможно и может быть довольно сбивающим с толку. Польза  императивного  и  объектно-ориентированного  программирования  состоит в том, что они разбивают код на изолированные модули, позволяя написание кода, сфокусированного на определенную проблему.

Как   правило,   объектно-ориентированные   методики   применяются   для   создания элементов  функциональности,  которые  обрабатывают данные,  а  методики  фунионального программирования применяются в тех обстоятельствах, когда данные не поддаются легкому описанию или проблему нельзя решить с помощью объеко-ориентированных подходов. Например, в примере контроллера освещения, рамотренного в главе 8, реализации  индивидуальных комнат и группировок комнат были бы оставлены в виде компонентов. Также было бы оставлено ядро, которое работает с  индивидуальными комнатами  и  группировками  комнат.  В данном слае  применение  функционального  программирования  не  принесло  бы  никакой пользы.  С  другой стороны,  пример электронной таблицы  в главе  11  был  бы  пррасным  кандидатом для  применения  функционального  программирования.  Идея данного  примера заключается  во  взаимодействии  с  различными  связанными  элентами  информации,  что трудно сделать с  помощью объектно-ориентированных подходов.  Другой ситуацией,  подходящей для  применения функционального  прраммирования, будет задача определения самого краткого маршрута между двумя

городами, рассмотренная в главе 4. Там проблема состояла в применении рекурсии и запоминания уже рассмотренных маршрутов.

Таким  образом,  в  одних  случаях  требуется  применение  императивных  методов, а в других — функциональных. Можно сказать, что объектно-ориентированное программирование чаще связано с решением проблем с данными и структурами данных, в то время как функциональное программирование — с созданием алгитмов, которые работают со структурами данных.

В конечном счете, ни функциональное, ни императивное программирование не яяется лучшим решением для всех проблем. Функциональное программирование имеет свои преимущества, также и как и императивное программирование. Решием, предлагаемым языком С#, является гибрид, позволяющий объединять метики функционального и императивного программирования.

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

  • Комментарии