Перейти к содержанию
Посмотреть в приложении

A better way to browse. Learn more.

Форум Академгородка, Новосибирск

A full-screen app on your home screen with push notifications, badges and more.

Чтобы установить это приложение на iOS и iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
Чтобы установить это приложение на Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Замыкания в C++

  • Ответов 75
  • Просмотры 13,8 тыс
  • Создана
  • Последний ответ

Топ авторов темы

Рекомендуемые сообщения

Опубликовано

2 consdush О чём я и пишу: ICommand с его потомками всего лишь эмуляция функционального типа и замыканий.

Реализация команд обычно тривиальна и совершенно шаблонна - т.е. это замыкания в чистом виде реализованные вручную. :)

 

Опубликовано

fiend

В смысле - и? К замыканиям и лямбдам это не имеет отношения, я же сказал.

Здесь интересно то что всякие связывания light, command, swtch - это вовсе не код, а конфигурация.

 

Tonal

Реализация команд обычно тривиальна и совершенно шаблонна - т.е. это замыкания в чистом виде реализованные вручную.

Не очень понял.

Кстати, что то плохо себе представляю, возможно ли с помощью замыканий (делегатом) сымитировать icommand с членами помимо execute() ... возможно конечно передавать весь набор делегатов какие есть в icommand, но стоит ли.

 

Теперь дошло. Назвается это не замыканиями, это inversion of control :) И вообще то Light у команды не замыкание.

Опубликовано
В смысле - и?

Извиняюсь за путаницу, надо было процитировать все Ваше сообщение.

 

К замыканиям и лямбдам это не имеет отношения, я же сказал.

В этом треде никто не просил показать, как писать конфигурацию для spring (тем более, с ошибками и без какого-либо форматирования в кусках кода). Это оффтоп, п. 13 правил форума.

 

Здесь интересно то что всякие связывания light, command, swtch - это вовсе не код, а конфигурация.

Вот про это и "И?". Кому интересно? Вам? Хотите поделиться? Создайте отдельную тему.

BTW, что может быть интересного в DI/IoC, как в шаблоне? Ничем он не интереснее того же итератора.

Опубликовано
fiend

В смысле - и? К замыканиям и лямбдам это не имеет отношения, я же сказал.

Ты видишь суслика?

А он есть!

Таки имеет. ICommand и пораждённые в шаблоне "команда" - эмуляция функционального типа и замыканий.

Если бы в Java или C# они (функц.типы и замыкания) были изначально, то и в шаблоне бы ICommand не понадобились.

Да и самого шаблона бы не осталось :)

 

Как никто ведь не описывает шаблон конкатенации строк на этих языках - есть прямая синтаксическая поддержка. :)

 

Tonal

Кстати, что то плохо себе представляю, возможно ли с помощью замыканий (делегатом) сымитировать icommand с членами помимо execute() ... возможно конечно передавать весь набор делегатов какие есть в icommand, но стоит ли.

А зачем там ещё какие-то члены?

Ты всё ещё о шаблоне "команда" рассуждаешь, или о чём-то другом?

 

Теперь дошло. Назвается это не замыканиями, это inversion of control :) И вообще то Light у команды не замыкание.

Наследование - практически единственный механизм в ООП, поэтому через него всё и делается. :)

Опубликовано
К замыканиям и лямбдам это не имеет отношения, я же сказал.

 

Раз топикстартер просил примеров с замыканиями, попробую немного исправить пример с IoC.

Для этого надо перемешать в голове все, связанное с "IoC", "DI", "lambda", "command" и "closure".

 

Note: В .NET реализации делегатов, на мой взгляд, не совсем корректно называть замыканиями, тем ни менее, далее 'замыкание' == 'делегат'.

 

Контейнер будет примитивный, статический, на замыканиях:

using System;
using System.Collections.Generic;

// static IoC FTW!
public static class Yoc {
    public enum Scope { Singleton, Factory }

    public static void Register<T>(string name, Func<T> activator) { Registry<T>.Add(activator, Scope.Singleton, name); }
    public static T Resolve<T>(string name) { return Registry<T>.Resolve(name); }

    private static class Registry<T>
    {
        private static readonly IDictionary<string, MutablePair> registrations = new Dictionary<string, MutablePair>();

        public static void Add(Func<T> activator, Scope scope, string name)
        {
            MutablePair pair;
            if (registrations.TryGetValue(name, out pair)) {
                pair.Scope = scope;
                pair.Activator = activator;
            } else {
                registrations.Add(name, new MutablePair { Scope = scope, Activator = activator });
            }
        }

        public static T Resolve(string name)
        {
            MutablePair registration;
            if (!registrations.TryGetValue(name, out registration)) {
                throw new ActivationException("Service: {0}; Named: '{1}'", typeof (T), name);
            }

            var service = registration.Activator();
            if (registration.Scope == Scope.Singleton) {
                registration.Activator = () => service;
            }
            return service;
        }

        private sealed class MutablePair { public Func<T> Activator; public Scope Scope; }
    }
}

public class ActivationException : Exception
{
    public ActivationException(string message, params object[] args) : base(string.Format(message, args)) {}
}

 

Вместо команд - замыкания. Да и контроллер, пусть, заодно, тоже будет замыканием :)

using System;
using System.Collections.Generic;
using System.Linq;

internal interface ILight { void LolOff(); void LolOn(); }

internal class UltravioletLight : ILight
{
    public void LolOn()  { Console.Out.WriteLine("On");  }
    public void LolOff() { Console.Out.WriteLine("Off"); }
}

internal static class Program
{
    private static void Main(string[] args)
    {
        int count;
        if (args.Length != 1 || !int.TryParse(args[0], out count) || count <= 0) {
            Console.Out.WriteLine("Usage: Epilepsia.exe <count>");
            return;
        }

        Configure();
        foreach (var toggleCommand in GenerateCommands(count)) {
            toggleCommand.Invoke();
        }
    }

    private static IEnumerable<Action> GenerateCommands(int count)
    {
        var random = new Random();
        var controller = Yoc.Resolve<Action<string>>("MyController");
        return from switches in Enumerable.Repeat(new[] { "ON", "OFF" }, count)
               select new Action(() => controller(switches[random.Next(2)]));
    }

    private static void Configure()
    {
        // remember kids: globals and untyped named registrations is cruise control for cool
        Yoc.Register<ILight>("MyLight", () => new UltravioletLight());
        
        Yoc.Register<Action>("MyLightOn", () => {
            var light = Yoc.Resolve<ILight>("MyLight");
            return light.LolOn;
        });

        Yoc.Register<Action>("MyLightOff", () => {
            var light = Yoc.Resolve<ILight>("MyLight");
            return light.LolOff;
        });
        
        Yoc.Register("MyCommandTable", () => new Dictionary<string, Action> {
                { "ON",  Yoc.Resolve<Action>("MyLightOn")  },
                { "OFF", Yoc.Resolve<Action>("MyLightOff") }
        });
        
        Yoc.Register<Action<string>>("MyController", () => {
            var table = Yoc.Resolve<Dictionary<string, Action>>("MyCommandTable");
            return switchName => table[switchName]();
        });
    }
}

Опубликовано

fiend

отвечать в таком духе не очень тактично. Изначально я написал, что сорри, оффтопик, в ответ мне - да ты что, это же оффтопик!! ну и как я должен отвечать? никак не буду. см певую строчку.

 

fiend

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

В общем то на прошлой странице были голоса про то что зачем замыкания нужны...

 

Tonal

И все таки, что если в интерфейсе ICommand есть еще члены? Например IsEnabled, Undo(), без разницы. Один член Excecute() это пардон вырожденная форма паттерна команды.

Получается что функциональный пример аналога ICommand годится только для вырожденного случая ICommand?

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

Опубликовано
Сегодня проскользнула в фидах презентация "Functional Programming with a Mainstream Language", в которой человек рассказывает как ему (и его команде) помог функциональный подход при создании приложения (вебсервиса?) на C#
Опубликовано
И все таки, что если в интерфейсе ICommand есть еще члены? Например IsEnabled, Undo(), без разницы. Один член Excecute() это пардон вырожденная форма паттерна команды.

Получается что функциональный пример аналога ICommand годится только для вырожденного случая ICommand?

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

Если есть еще члены, то это уже не чистая команда, а команда + что-то ещё.

И это что-то вполне можно и нужно отделить.

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

 

Шаблон команда, описывает как можно в ООЯ собрать в кучу действие с его аргументами в одной части системы и передать на выполнение в другую часть.

Куда и зачем нужно будет передавать действие, которое нельзя выполнять (IsDisabled)?

Т.е. IsEnabled/IsDisabled это не свойство команды, а свойство элементов управления, которые генерят команды.

 

С Undo сложнее, т.к. сам механизм и его цели могут быть существенно разными в зависимости от.

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

Опубликовано

AmbassadorKosh

Спасибо конечно за ссылку. Немного напоминает Нашу Рашу.

 

Tonal

Если есть еще члены, то это уже не чистая команда, а команда + что-то ещё.

Не чистая, а примитивная, она же функция обратного вызова, он же делегат. Не буду спорить что каркас возможно построить на делегатах, но все таки если каркас спроектирован с IsEnabled вместе с Execute и Undo, то это уже будет действительно ICommand, а не простой колбэк. Суть ICommand в колбэке, но так как ICommand все таки находится в сфере оод, а не функционального программирования, то иметь члены помимо колбэка ему полагается по происхождению. В этом его преимущество, это не просто колбэк, а объект команды. В конкретных реализациях он обрастает частными членами, необходимыми в контексте модуля где ICommand объявлен.

 

Берем самый простой случай функции которая не принимает параметров и не возвращает ничего. Начинаем усложнять - добаляем логику модуля где функция могла бы использоваться. При небольшом усложнении появятся аргументы и возвращаемое значение. Если еще усложнить и сделать шаг в сторону ООД, то колбэк станет объектом и у него появятся члены помимо Excecute(). Это ж естественно.

 

Куда и зачем нужно будет передавать действие, которое нельзя выполнять (IsDisabled)?

Передавать действие надо туда где ICommand используется. UI кнопка, элемент меню, клавиша быстрого доступа, IsEnabled - кнопка может быть задизэйблена, меню тоже, клавиша игнорируется и тп.

 

вернуть из функции для действия функцию для отмены.

Как насчет варианта требований к ICommand что с его помощью нужно получать сведения о том, может ли он делать Undo после Excecute. Добавить член CanUndo или может вернуть из Execute структурку с членом CanUndo? Вариант очевиден.

Опубликовано

Ты путаешь и смешиваешь уровни, как мне кажется. :)

 

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

Кнопки, пункты меню, клавиши быстрого доступа - они все только инициируют посылку команды туда, где она должна быть выполнена.

Удобно обобщить их общие элементы в одном месте, но это будет не "команда", а что-то другое. :)

 

Например в Borland VCL это называется TAction и её производные, в Qt - QAction.

У них есть текст, текст подсказки, иконка, состояние разрешенности (isEnabled), видимость (isVisible) и ещё много полезных атрибутов и методов.

Эти классы очень удобны на уровне пользовательского интерфейса, но на уровне предметной логики существенно только то, что они могут создать и отправить команду.

 

Про Undo - опять же отдельная песня.

Под Undo можно понимать очень много совершенно разных механизмов, поэтому говорить об этом без знания конкретной архитектуры системы, её предметной логики бессмысленно.

Простейшее Undo, где откат есть просто инвертированное действие возможно только для текста: добавил символ - убрал символ, но и там уже не так тривиально. Например ворд убирает всё слово, хотя мы вводили его по символам...

Уже для редактирования графики инвертирование действия не даст желаемого эффекта - большое количество действий необратимы.

То же самое для любых вычислений с точкой. :)

То же самое в конкурентной среде - выполнив танзакцию что надо сделать, чтобы получить предыдущее для тебя состояние? И будет ли это осмысленным?

 

Так что вопрос с Undo-й решается не на уровне класса команды, введением 1, 2х, 3х методов, а на уровне архитектуры. И задействует несколько шаблонов. :)

 

Берем самый простой случай функции которая не принимает параметров и не возвращает ничего

Функция main Фотошопа подойдёт? :)

Опубликовано

Tonal

Не согласен практически со всеми заключениями имеющими отнешение к делу.

 

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

 

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

Поэтому делать акцент именно на передаче я бы не стал.

Например передача действия маршалингом использует совсем другие паттерны.

 

У команды есть отличие от колбэка, для нее справедливо то что говорится в функциональном контексте, за это отвечает член execute() + добавляется объектное поведение.

 

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

 

Кнопки, пункты меню, клавиши быстрого доступа - они все только инициируют посылку команды туда, где она должна быть выполнена.

Удобно обобщить их общие элементы в одном месте, но это будет не "команда", а что-то другое

Почему что то другое? IsEnabled, Name и тп неужели не имеют отношения к колбэку execute()? Чем плохо иметь в команде член Имя с точки зрения ООД?

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

 

.. TAction ...

У них есть текст, текст подсказки, иконка, состояние разрешенности (isEnabled), видимость (isVisible) и ещё много полезных атрибутов и методов.

Эти классы очень удобны на уровне пользовательского интерфейса, но на уровне предметной логики существенно только то, что они могут создать и отправить команду.

 

TAction, если я правильно понимаю, и есть команда. Насчет предметной логики, почему IsEnabled несущественен на "уровне предметной логики"? Имплементация IsEnabled прекрасно может обращаться к предметной логике за вычислением своего значения.

 

Сама предметная логика скорее всего и не знает про команды UI слоев, и вообще как UI организован.

 

Для интереса просто приведите 2 примера системы где ICommand имеет единственный член Execute.

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

Поэтому делать акцент именно на передаче я бы не стал.

Перечитай GoF.

3.2.3 Команда (Command), Действие (Action) или Транзакция (Транзакция) - GoF

Проблема Необходимо послать объекту запрос, не зная о том, выполнение какой операции запрошено и кто будет получателем.

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

 

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

Отсюда

 

Сама предметная логика скорее всего и не знает про команды UI слоев, и вообще как UI организован.

 

Для интереса просто приведите 2 примера системы где ICommand имеет единственный член Execute.

Первое предложение отвечает на второе - в предметной логике ничего кроме Execute от команды и не нужно. :)

Опубликовано

Tonal

В предметной логике ничего кроме Execute от команды и не нужно.

Не понял. Допустим, команды находятся в библиотеке UI, а в предметной логике есть объект Item у него есть метод Delete() и свойство CanDelete. Я так делал не раз кстати ибо в CanDelete прекрасно помещается та самая логика.

В этом случае Execute() команды будет вызывать Item.Delete, а IsEnabled - CanDelete.

 

Это правда прямолинейный случай когда имеются аналогии одновременно в UI библиотеке и предметной логике.

 

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

 

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

 

Проблема Необходимо послать объекту запрос, не зная о том, выполнение какой операции запрошено и кто будет получателем.

Ну я так думаю тут акцент не на посылке, а на анонимности операции. См случай маршалинга, где стоит проблема посылки :)

 

И все таки как насчет примеров?

 

К замыканиям тема не относится, опять оффтопик.

 

Еще пример (воображаемый) когда у команды естественно добавить дополнительный член. Например обработчик задач запускает на исполнение команды согласно приоритетам. Тогда в ITask логично добавить Priority. Ну у меня фантазия небогатая.. или возможно в ITask команду лучше бы включить как член..

Опубликовано
Tonal

В предметной логике ничего кроме Execute от команды и не нужно.

Не понял. Допустим, команды находятся в библиотеке UI, а в предметной логике есть объект Item у него есть метод Delete() и свойство CanDelete. Я так делал не раз кстати ибо в CanDelete прекрасно помещается та самая логика.

В этом случае Execute() команды будет вызывать Item.Delete, а IsEnabled - CanDelete.

Ты думаешь об этом шаблоне исключительно в пределах UI.

А исходный шаблон описывает не только UI, но и предметную логику - не зря его второе название - транзакция.

Например, веб-фреймворк. Каждый запрос в нём - комманда серверу сгенерить следующую порцию данных.

Понятно, что в этой команде нет ни IsEnabled, ни Name, ни Undo, ни остальных полезных и нужных в UI вещей - они там не нужны. :)

 

Кстати есть веб-фреймворки, в которых на клиент передаются именно сохранённые функции, и очередной запрос - это передача одной из этмх функций обратно на сервер для обработки. :)

 

И все таки как насчет примеров?

Ну и какие я приведу примеры, если у нас с тобой разное понимание шаблона команда? :)

Для своей интерпретации я уже приводил. :)

 

Для твоей - выигрыш тоже очивиден. Можно обойтись без интерфейса ICommand.

Вместо него создадим финальный класс со всеми нужными атрибутами.

И дополним их число атрибутами doExecute, doUndo, getIsEnabled - в которых сохраним замыкания для выполнения соответствующих действий.

А его методы Execute, Undo, IsEnabled - просто дёргают эти сохранённые замыкания.

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

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

Аккаунт

Навигация

Поиск

Поиск

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.