Подтвердить что ты не робот

Закрытие: почему они так полезны?

Как разработчик OO, возможно, мне трудно понять его ценность. Какую добавленную стоимость они дают? Они вписываются в мир ОО?

4b9b3361

Ответ 1

Закрытие не дает вам дополнительной мощности.

Все, что вы можете достичь с ними, вы можете достичь без них.

Но они очень полезны для того, чтобы сделать код более понятным и понятным. И, как мы все знаем, чистый читаемый короткий код - это код, который легче отлаживать и содержит меньше ошибок.

Позвольте мне привести короткий пример Java возможного использования:

    button.addActionListener(new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
            System.out.println("Pressed");
        }
    });

Будет заменен (если у Java было закрытие):

button.addActionListener( { System.out.println("Pressed"); } );

Ответ 2

Вы можете видеть это как обобщение класса.

В вашем классе есть определенное состояние. Он имеет некоторые переменные-члены, которые могут использовать его методы.

Закрытие - это просто более удобный способ предоставления функции доступа к локальному состоянию.

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

Когда вы определяете метод-член на традиционном языке ООП, его закрытие - "все члены, видимые в этом классе".

Языки с "правильной" поддержкой закрытия просто обобщают это, поэтому закрытие функции - это "все видимые здесь переменные". Если "здесь" - это класс, то у вас есть традиционный метод класса.

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

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

Ответ 3

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

Например, обычное использование в JavaScript - это запуск HTTP-запроса. Кто бы ни начинал, вероятно, хочет контролировать, что происходит, когда приходит ответ. Итак, вы сделаете что-то вроде этого:

function sendRequest() {
  var requestID = "123";
  Ext.Ajax.request({
    url:'/myUrl'
    success: function(response) {
      alert("Request " + requestID + " returned");
    }
  });
}

Из-за закрытия JavaScript переменная "requestID" фиксируется внутри функции успеха. Это показывает, как вы можете писать функции запроса и ответа в одном месте и обмениваться переменными между ними. Без замыканий вам нужно передать запросID в качестве аргумента или создать объект, содержащий requestID и функцию.

Ответ 4

IMHO сводится к возможности захвата блоков кода и их контекста, на который нужно ссылаться в какой-то момент позже и выполняться, когда/if/по мере необходимости.

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

[править - пример кода на основе вышеприведенного комментария]

Java:

List<Integer> numbers = ...;
List<Integer> positives = new LinkedList<Integer>();
for (Integer number : integers) {
    if (number >= 0) {
        positives.add(number);
    }
}

Scala (пропуская некоторые другие тонкости, такие как вывод типа и подстановочные знаки, поэтому мы сравниваем эффект закрытия):

val numbers:List[Int] = ...
val positives:List[Int] = numbers.filter(i:Int => i >= 0)

Ответ 5

Жаль, люди больше не учатся Smalltalk в edu; там, замыкания используются для структур управления, обратных вызовов, перечисления коллекции, обработки исключений и т.д. Для небольшого примера, вот поток обработчика действий рабочего очереди (в Smalltalk):

|actionQueue|

actionQueue := SharedQueue new.
[
    [
        |a|

        a := actionQueue next.
        a value.
    ] loop
] fork.

actionQueue add: [ Stdout show: 1000 factorial ].

а для тех, кто не умеет читать Smalltalk, то же самое в синтаксисе JavaScript:

var actionQueue;

actionQueue = new SharedQueue;
function () {
    for (;;) {
        var a;

        a = actionQueue.next();
        a();
    };
}.fork();

actionQueue.add( function () { Stdout.show( 1000.factorial()); });

(ну, как видите: синтаксис помогает при чтении кода)

Изменить: обратите внимание, как называется действиеQueue изнутри блоков, что работает даже для разветвленного блока потоков. То, что делает закрытие настолько простым в использовании.

Ответ 7

Закрытие очень хорошо вписывается в мир ОО.

В качестве примера рассмотрим С# 3.0: он имеет замыкания и многие другие функциональные аспекты, но все еще является очень объектно-ориентированным языком.

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

Таким образом, использование закрытий обычно представляет собой детали реализации в объектно-ориентированном коде.

Я использую их все время, так как этот фрагмент кода из одного из наших модульных тестов (против Moq) показывает:

var typeName = configuration.GetType().AssemblyQualifiedName;

var activationServiceMock = new Mock<ActivationService>();
activationServiceMock.Setup(s => s.CreateInstance<SerializableConfigurationSection>(typeName)).Returns(configuration).Verifiable();

Было бы довольно сложно указать входное значение (typeName) как часть ожидания Mock, если оно не было для функции закрытия С#.

Ответ 8

Что касается заключительного запроса: "Do (замыкания) подходят в мире OO?"

На многих языках замыкания, а также первоклассные функции обеспечивают основу для разработки программ OO: Javascript, Lua и Perl приходят на ум.

В еще одном "традиционном" языке OO, с которым я знаком, Java, есть 2 основных отличия:

  • Функции не являются конструкциями первого класса
  • В Java детали реализации OO (независимо от того, используются ли блокировки внутри) не отображаются непосредственно разработчику, как в Javascript, Lua и Perl

Поэтому на "традиционном OO" языке, таком как Java, добавление замыканий в значительной степени является таким синтаксическим сахаром.

Ответ 9

Возможно, в мире скомпилированного программирования преимущества замыканий менее заметны. В закрытии JavaScript невероятно мощные. Это происходит по двум причинам:

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

2) JavaScript - это лямбда-язык. Это означает, что в функциях JavaScript объекты первого класса, которые определяют область и область действия родительской функции, доступны для дочерних объектов. Это важно, поскольку переменная может быть объявлена ​​в родительской функции, используемой в дочерней функции, и сохранить значение даже после возвращения дочерней функции. Это означает, что переменная может повторно использоваться функцией много раз со значением, уже определенным последней итерацией этой функции.

В результате замыкания невероятно мощны и обеспечивают превосходную эффективность в JavaScript.

Ответ 10

глядя выше примеров, я могу добавить свой бит.

  • Я ценю стиль, скрывающую состояние часть и цепочку выражения, но этого недостаточно

  • Многое можно сказать о простом и явном коде

  • Я чувствую, что Scala, Perl и некоторые другие языки типа Scheme предназначены для того, чтобы сделать вид сокращения для конкретного способа мышления разработчиком языка или сделать его более продуктивным.

Я бы использовал простоту python и раннего синтаксиса java и т.д. как лучший способ простоты и ясности.

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

необходимы блокировки, но не так часто, чтобы гарантировать, что они будут гражданами первого класса.