Чистая архитектура. Искусство разработки программного обеспечения - страница 20



.

Если система состоит из модулей, которые можно развертывать независимо, их можно разрабатывать независимо, разными командами. Это независимость разработки.

Заключение

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

6. Функциональное программирование



Многие идеи функционального программирования появились задолго до появления самого программирования. Эта парадигма в значительной мере основана на λ-исчислении, изобретенном Алонзо Чёрчем в 1930-х годах.

Квадраты целых чисел

Суть функционального программирования проще объяснить на примерах. С этой целью исследуем решение простой задачи: вывод квадратов первых 25 целых чисел (то есть от 0 до 24).

В языках, подобных Java, эту задачу можно решить так:


>public class Squint {

> public static void main(String args[]) {

> for (int i=0; i<25; i++)

> System.out.println(i*i);

> }

>}


В Clojure, функциональном языке и производном от языка Lisp, аналогичную программу можно записать так:


>(println (take 25 (map (fn [x] (* x x)) (range))))


Этот код может показаться немного странным, если вы не знакомы с Lisp. Поэтому я, с вашего позволения, немного переоформлю его и добавлю несколько комментариев.

>(println;___________________ Вывести

> (take 25;_________________ первые 25

> (map (fn [x] (* x x));__ квадратов

> (range))));___________ целых чисел


Совершенно понятно, что >println, >take, >map и >range – это функции. В языке Lisp вызов функции производится помещением ее имени в круглые скобки. Например, >(range) – это вызов функции range.

Выражение >(fn [x] (* x x)) – это анонимная функция, которая, в свою очередь, вызывает функцию умножения и передает ей две копии входного аргумента. Иными словами, она вычисляет квадрат заданного числа.

Взглянем на эту программу еще раз, начав с самого внутреннего вызова функции:


• функция >range возвращает бесконечный список целых чисел, начиная с 0;

• этот список передается функции >map, которая вызывает анонимную функцию для вычисления квадрата каждого элемента и производит бесконечный список квадратов;

• список квадратов передается функции >take, которая возвращает новый список, содержащий только первые 25 элементов;

• функция >println выводит этот самый список квадратов первых 25 целых чисел.


Если вас напугало упоминание бесконечных списков, не волнуйтесь. В действительности программа создаст только первые 25 элементов этих бесконечных списков. Дело в том, что новые элементы бесконечных списков не создаются, пока программа не обратится к ним.

Если все вышесказанное показалось вам запутанным и непонятным, тогда можете отложить эту книгу и прекрасно провести время, изучая функциональное программирование и язык Clojure. В этой книге я не буду рассматривать эти темы, так как не это является моей целью.

Моя цель – показать важнейшее отличие между программами на Clojure и Java. В программе на Java используется изменяемая переменная – переменная, состояние которой изменяется в ходе выполнения программы. Это переменная i – переменная цикла. В программе на Clojure, напротив, нет изменяемых переменных. В ней присутствуют инициализируемые переменные, такие как