Re[2]: Chain of responsibility
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 04.09.06 07:45
Оценка: -1
Здравствуйте, vse_ravno_ya_budu_anonim, Вы писали:

___>Именно так и происходит. Обрабатывает запрос один компонент и возвращает результат. А если компонент не может обработать запрос, он передает его дальше.


Все-таки лучше отделить поиск компонента для обработки от самой обработки. Т.е. есть набор объектов-обработчиков, которые могут быть сгруппированы:

а) в массив;
б) в список;
в) в очередь;
г) в стек;
д) в матрицу;
е) в дерево;
ж) в граф;
з) и т.д.

Соответственно, существуют два процесса (две функции):

1) процесс поиска нужного обработчика из набора;
2) процесс обработки (вызова функции обработчика).

Именно таким образом организована обработка сообщений в профессиональных GUI-библиотеках — MFC, OWL.

А Chain of Responsibility — лишь частный случай этого решения. Кстати, в этом и заключается слабость паттернов GoF. Книга представляет собой просто набор частных случаев. Не рассматривается развитие идей решений.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[7]: Chain of responsibility
От: Аноним  
Дата: 05.09.06 05:03
Оценка: +1
Здравствуйте, Кирилл Лебедев, Вы писали:


КЛ>Оба утверждения не соответствуют истине. Постараюсь это показать.


КЛ>Относительно 1.


КЛ>Есть 2 объекта:


КЛ>1) Хранитель обработчиков, который хранит объекты, как удобнее (в виде очереди, списка, массива, дерева и т.п.).

КЛ>2) Поисковик подходящего объекта, который ищет по заданному алгоритму (первый подходящий, последний подходящий или какому -либо другому правилу) в Хранителе.

как поисковик узнаёт что объект подходит для обработки сообщения? приведите пример реализации и вы увидите что вощникнет проблема...


КЛ>Относительно 2.


КЛ>А теперь мысленно представьте, что объектов типа C и D у Вас не 2, а десяток, сотня, тысяча. Каждый из них перехватывает какое-нибудь сообщение, преобразует в другое и отсылает другому объекту, который его преобразует и отсылает еще какому-нибудь объекту. Вам будет удобно сопровождать такую систему? Думаю, что очень быстро Вы запутаетесь и перестанете понимать, какое действие следует за каким действием.


КЛ>Chain of Responsibility имеет существенные ограничения на длину цепочки.

а если у вас будет здоровый класс, содержащий тысячи строк логики корму в каких случаях и когда что отсылать не запутаетесь ли вы что к чему и как поддерживать? Про ограничение на долину цепочки не согласен, не вижу серьёзной аргументации, разве что группировать наверно лучше в некоторую иерархическую структуру. Посмотрите архитектуру драйверов в windows — там как раз цепочка фильтров обработчиков... может не самый хороший пример но всё же.
Chain of responsibility
От: Aviator  
Дата: 03.09.06 19:49
Оценка:
Пристально посмотрев на этот паттерн пришёл к выводу, что в нём чего то не хватает для законченности . Тпичная задача: есть набор компонент (классов), пердоставляющих некоторый набор сервисов. Соединяем всё это добро в оддно связанное приложение, в котором источниками и обработчиками запросов выступает этот набор компонент. И тут натыкаемся на проблему — во первых если один компонент инициирует некоторый запрос, вызывая при этом _nextComponent->Handle(aRequest), обраьотать запрос смогут только нижестоящие в списке компоненты... Далее, нередко требуется что бы обработать запрос мог только один компонент и при этом вернуть инициирующему запрос объекту результат... И на последок — в некоторых случаях компонент должен быть уверен, что созданный им запрос был получен всеми объектами в цепочке... Ну и напоследок — требуется средство формирование очереди, что бы некотрые объекты могли раньше получать сообщения... Вобщем по моему в классическом варианте от GoF много непоняток. Есть идеии как формализовать это всё хозяйство?
Re: Chain of responsibility
От: vse_ravno_ya_budu_anonim  
Дата: 04.09.06 06:11
Оценка:
Здравствуйте, Aviator, Вы писали:

A>Далее, нередко требуется что бы обработать запрос мог только один компонент и при этом вернуть инициирующему запрос объекту результат...


Именно так и происходит. Обрабатывает запрос один компонент и возвращает результат. А если компонент не может обработать запрос, он передает его дальше.

A>И на последок — в некоторых случаях компонент должен быть уверен, что созданный им запрос был получен всеми объектами в цепочке...


Ну это да, об этом и упоминается — "получение не гарантировано".

A>Ну и напоследок — требуется средство формирование очереди, что бы некотрые объекты могли раньше получать сообщения...


Ну это, видимо, будет совсем другой паттерн. Скажи, какие у тебя задачи, постараюсь помочь чем смогу.
Re[2]: Chain of responsibility
От: Аноним  
Дата: 04.09.06 06:27
Оценка:
Здравствуйте, vse_ravno_ya_budu_anonim, Вы писали:

___>Здравствуйте, Aviator, Вы писали:


A>>Далее, нередко требуется что бы обработать запрос мог только один компонент и при этом вернуть инициирующему запрос объекту результат...


___>Именно так и происходит. Обрабатывает запрос один компонент и возвращает результат. А если компонент не может обработать запрос, он передает его дальше.

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

A>>И на последок — в некоторых случаях компонент должен быть уверен, что созданный им запрос был получен всеми объектами в цепочке...


___>Ну это да, об этом и упоминается — "получение не гарантировано".


обработан всеми означает, что каждый ПОЛУЧИТ возможность его обработать, то есть ни у какого компонента не будет возможность прервать цепочку

A>>Ну и напоследок — требуется средство формирование очереди, что бы некотрые объекты могли раньше получать сообщения...


___>Ну это, видимо, будет совсем другой паттерн. Скажи, какие у тебя задачи, постараюсь помочь чем смогу.


почему же другой, не другной а доработанный chain of responsibility .

PS задача простая — хочется собрать набор компонент, на которые разбита исходная задача с минимальной связностью между ними и максимальной расширяемостью.
Re[3]: Chain of responsibility
От: Аноним  
Дата: 04.09.06 08:06
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, vse_ravno_ya_budu_anonim, Вы писали:


___>>Именно так и происходит. Обрабатывает запрос один компонент и возвращает результат. А если компонент не может обработать запрос, он передает его дальше.


КЛ>Все-таки лучше отделить поиск компонента для обработки от самой обработки. Т.е. есть набор объектов-обработчиков, которые могут быть сгруппированы:


важным элементом является тот факт, что задачу определения кому предназнасчен запрос решает сам компонент.
Re[3]: Chain of responsibility
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 04.09.06 08:30
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, vse_ravno_ya_budu_anonim, Вы писали:


___>>Именно так и происходит. Обрабатывает запрос один компонент и возвращает результат. А если компонент не может обработать запрос, он передает его дальше.


КЛ>Все-таки лучше отделить поиск компонента для обработки от самой обработки. Т.е. есть набор объектов-обработчиков, которые могут быть сгруппированы:


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

КЛ>Соответственно, существуют два процесса (две функции):


КЛ>1) процесс поиска нужного обработчика из набора;

КЛ>2) процесс обработки (вызова функции обработчика).

КЛ>Именно таким образом организована обработка сообщений в профессиональных GUI-библиотеках — MFC, OWL.


MFC, к примеру, уже давно лежит в земле.

КЛ>А Chain of Responsibility — лишь частный случай этого решения. Кстати, в этом и заключается слабость паттернов GoF.


Это очень "интересное" мнение я слышу в первый раз. Тема для книги есть — "Слабость паттернов GoF".

КЛ>Книга представляет собой просто набор частных случаев.


Есть ли у Вас более конкретные доводы? Паттерн — это и есть частный случай и они не призваны решать все Ваши проблемы.

КЛ>Не рассматривается развитие идей решений.


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

Касательно вопроса Автора ветки.

  1. "Добавить возможность посылки сообщения не только нижестоящим" — добавьте в интерфейс обработчика не только ссылку на следующий обработчик, но на голову списка.
  2. "в некоторых случаях компонент должен быть уверен, что созданный им запрос был получен всеми объектами в цепочке..." — добавьте в объект запроса логинрование проходящих им обработчиков, то есть пусть каждый обработчик вызывает метод запроса Log и после прохождения цепи спросите у запроса, кто его получил.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Chain of responsibility
От: Аноним  
Дата: 04.09.06 09:31
Оценка:
Здравствуйте, pt4h, Вы писали:


P>
  • "в некоторых случаях компонент должен быть уверен, что созданный им запрос был получен всеми объектами в цепочке..." — добавьте в объект запроса логинрование проходящих им обработчиков, то есть пусть каждый обработчик вызывает метод запроса Log и после прохождения цепи спросите у запроса, кто его получил.
    P>[/list]

    не в этом задача нужно что бы никакой компонент в цепочке для некоторых сообщений не имел возможности прервать обработку, отказавшись вызвать next->Handle(theRequest)
  • Re[5]: Chain of responsibility
    От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
    Дата: 04.09.06 09:56
    Оценка:
    Здравствуйте, <Аноним>, Вы писали:

    А>Здравствуйте, pt4h, Вы писали:



    P>>
  • "в некоторых случаях компонент должен быть уверен, что созданный им запрос был получен всеми объектами в цепочке..." — добавьте в объект запроса логинрование проходящих им обработчиков, то есть пусть каждый обработчик вызывает метод запроса Log и после прохождения цепи спросите у запроса, кто его получил.
    P>>[/list]

    А>не в этом задача нужно что бы никакой компонент в цепочке для некоторых сообщений не имел возможности прервать обработку, отказавшись вызвать next->Handle(theRequest)


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

    Ниже реализация "сходу" для примера:

    public interface IRequestHandler
    {
        object Handle (IRequest request, IChainSurrogate chain);
        
        bool CanHandle (IRequest request);
    }
    
    public interface IChainSurrogate
    {
        void Register(IRequestHandler handler);
        
        void UnRegister(IRequestHandler handler);
        
        object Accept(IRequest request);
    }
    
    public class StrictChainOfResponsibility : IChainSurrogate
    {
        private IList<IRequestHandler> handlers;
        
        public void Register(IRequestHandler handler)
        {
            this.handlers.Add(handler);
        }
        
        public void UnRegister(IRequestHandler handler)
        {
            this.handerls.Remove(handler);
        }
        
        public object Accept(IRequest request)
        {
            // Вот тут мы можем утсанавливать свои правила по обработке
            foreach (IRequestHandler r in this.handlers)
            {
                // Например, все должны его обработать, если могут
                if (r.CanHandle(request))
                {
                    // Вот тут мы можем еще одно событие запостить используя IChainSurrogate интерфейс
                    r.Handle(request, this);
                }
            }
        }
    }


    Повторюсь, этот код уже далеко не "оригинальная" Chain of Responsibility.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
  • Re[6]: Chain of responsibility
    От: Аноним  
    Дата: 04.09.06 10:19
    Оценка:
    Здравствуйте, pt4h, Вы писали:

    P>Повторюсь, этот код уже далеко не "оригинальная" Chain of Responsibility.


    согласен с реализацией, оригинальные паьттерны в чистом виде я пока на практике не встречал
    Re[4]: Chain of responsibility
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 04.09.06 11:45
    Оценка:
    Здравствуйте, pt4h, Вы писали:

    КЛ>>Все-таки лучше отделить поиск компонента для обработки от самой обработки. Т.е. есть набор объектов-обработчиков, которые могут быть сгруппированы:


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


    Необязательно. Можно ввести два объекта:

    1) Хранильщик обработчиков.
    2) Поисковик обработчика.

    Хранильщик хранит все обработчики, а поисковик последовательно получает их из хранильщика при помощи специфицированного интерфейса. Что в этом плохого?

    P>MFC, к примеру, уже давно лежит в земле.


    Это никак не свидетельствует о плохом качестве локальных решений.

    P>Это очень "интересное" мнение я слышу в первый раз. Тема для книги есть — "Слабость паттернов GoF".


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

    P>Есть ли у Вас более конкретные доводы? Паттерн — это и есть частный случай и они не призваны решать все Ваши проблемы.


    Свои доводы (относительно Chain Of Responsibility) я привел выше. Могу повторить:

    1) Этот паттерн подразумевает только один способ группировки данных — список.
    2) Сам контейнер (список) не отделен от хранимых в нем данных. А эта особенность характерна только для устаревших языков программирования, например, Си.
    3) Функция поиска (принятия решения) смешена с операцией выполнения принятого решения (обработки команды). Что тоже плохо. Текущая тенденция — разделение этих функций.

    P>Каждый паттерн в книге GoF несет только необходимую информацию, если говорить о развитии идей решений. Все остальное — это комбинирование паттернов.


    Это слишком упрощенное представление.
    С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re[4]: Chain of responsibility
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 04.09.06 11:50
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>важным элементом является тот факт, что задачу определения кому предназнасчен запрос решает сам компонент.


    Это плохо. Нужно разделять, а не смешивать ответственность. Можно сделать так:

    1) Алгоритм поиска подходящего обработчика предоставляет структуру данных (набор критериев), которая заполняется обработчиком.
    2) На основе заполненной структуры данных алгоритм поиска обработчика принимает решение (делает выбор).

    Т. обр., обработчик заполняет структуру данных (подбирает значения для критериев), а алгоритм поиска — делает выбор.
    С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re[5]: Chain of responsibility
    От: Аноним  
    Дата: 04.09.06 11:59
    Оценка:
    Здравствуйте, Кирилл Лебедев, Вы писали:

    КЛ>Здравствуйте, Аноним, Вы писали:


    А>>важным элементом является тот факт, что задачу определения кому предназнасчен запрос решает сам компонент.


    КЛ>Это плохо. Нужно разделять, а не смешивать ответственность. Можно сделать так:


    совершенно не согласен! наоборот логично что каждый компонент сам отвечает что он обрабатывает тем самым мзолирую объединяющее звено от бизнес логики. Таким образом мы достигаем высокой степени гибкости приложения, когда легко добавляются новые компоненты и новые запросы. Если решение кто что обрабатывает принимаепт центральное звено то мы помещаем большую. часть доменной логики в один компонент и тем самым катострофически уменьшаем гибкость и усиливаем связность.
    Re[5]: Chain of responsibility
    От: Аноним  
    Дата: 04.09.06 12:04
    Оценка:
    Здравствуйте, Кирилл Лебедев, Вы писали:

    а теперь в противовес вышесказанному простой пример — есть два комопнента — первый А отсылает RequestA, который ловит второй компонент B. я хочу добавить компонент C, который будет перехватывать запрос RequestA, создавать RequestAB и оьтсылать его на обработку компоненту D, который в свою очередь формирует новый запрос RequestA и пересылает его в некотором виде компоненту B. В архитектуре без центрального звена это делает прозрачно добавлением двух компонент и редактирыванием некого конфигурационного файла, при этом алгоритм может изменится до неузнаваемости. А в вашем варианте придётся править некоторое общее для _всех_ компонент звено, пересобирать систему и получить кучу гемора в поддержке...
    Re[5]: Chain of responsibility
    От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
    Дата: 04.09.06 12:05
    Оценка:
    Здравствуйте, Кирилл Лебедев, Вы писали:

    КЛ>Здравствуйте, Аноним, Вы писали:


    А>>важным элементом является тот факт, что задачу определения кому предназнасчен запрос решает сам компонент.


    КЛ>Это плохо. Нужно разделять, а не смешивать ответственность. Можно сделать так:


    КЛ>1) Алгоритм поиска подходящего обработчика предоставляет структуру данных (набор критериев), которая заполняется обработчиком.

    КЛ>2) На основе заполненной структуры данных алгоритм поиска обработчика принимает решение (делает выбор).

    КЛ>Т. обр., обработчик заполняет структуру данных (подбирает значения для критериев), а алгоритм поиска — делает выбор.


    В этом решении есть несколько проблем:
    1. Если набор данных, которые необходимо заполнять изменяется, изменения придется вносить во все обработчики.
    2. Так как мы не привязываемся к обработчику, то каждый из них может быт исключительно уникальным и соответственно данные и критерии могут быть абсолютно разными. В итоге эта структура соберет в себя все возможные критерии.
    3. Если критерии не могу быть представлены в виде выделнных данных, а являются скажем результатом выполнения какого-то алгоритма в момент обработки данных — поиск по критерию тоже не будет работать.
    4. Количество структур поиска будет расти вместе с количеством событий.

    Все эти проблемы будут неизбежно вести к изменениям в структуре поиска и обработчиках, что не хорошо в нашем случае, так как мы стараемся не привязываться к обработчику.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[5]: Chain of responsibility
    От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
    Дата: 04.09.06 12:16
    Оценка:
    Здравствуйте, Кирилл Лебедев, Вы писали:

    КЛ>Здравствуйте, pt4h, Вы писали:


    КЛ>>>Все-таки лучше отделить поиск компонента для обработки от самой обработки. Т.е. есть набор объектов-обработчиков, которые могут быть сгруппированы:


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


    КЛ>Необязательно. Можно ввести два объекта:


    КЛ>1) Хранильщик обработчиков.

    КЛ>2) Поисковик обработчика.

    КЛ>Хранильщик хранит все обработчики, а поисковик последовательно получает их из хранильщика при помощи специфицированного интерфейса. Что в этом плохого?


    К этому вопросу в посте
    Автор: pt4h
    Дата: 04.09.06
    выше по ветке.

    КЛ>Свои доводы (относительно Chain Of Responsibility) я привел выше. Могу повторить:


    КЛ>1) Этот паттерн подразумевает только один способ группировки данных — список.


    Он не определяет никаких способов группировки Можно построить дерево и обходить его.

    КЛ>2) Сам контейнер (список) не отделен от хранимых в нем данных. А эта особенность характерна только для устаревших языков программирования, например, Си.


    Учитывая пункт 1 нет ничего плохо в том, что мы храним ссылки на "элементы". Если мы выбираем контейнер, мы подвергаем ограничениям способ выбора следующего обработчика. Пол цепи может быть списком, пол деревом

    КЛ>3) Функция поиска (принятия решения) смешена с операцией выполнения принятого решения (обработки команды). Что тоже плохо. Текущая тенденция — разделение этих функций.


    Разделение в данном случае приведет к 2N классам вместо N и разбрасываение обязанностей приведет к сложному сопровождению и пониманию.

    P>>Каждый паттерн в книге GoF несет только необходимую информацию, если говорить о развитии идей решений. Все остальное — это комбинирование паттернов.


    КЛ>Это слишком упрощенное представление.


    Паттерны — это строительные кирпичики. Кирпич не лолжен сразу же содержать встроенную розетку
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[6]: Chain of responsibility
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 04.09.06 13:41
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>а теперь в противовес вышесказанному простой пример — есть два комопнента — первый А отсылает RequestA, который ловит второй компонент B. я хочу добавить компонент C, который будет перехватывать запрос RequestA, создавать RequestAB и оьтсылать его на обработку компоненту D, который в свою очередь формирует новый запрос RequestA и пересылает его в некотором виде компоненту B. В архитектуре без центрального звена это делает прозрачно добавлением двух компонент и редактирыванием некого конфигурационного файла, при этом алгоритм может изменится до неузнаваемости. А в вашем варианте придётся править некоторое общее для _всех_ компонент звено, пересобирать систему и получить кучу гемора в поддержке...


    В Вашем сообщении содержатся 2 утверждения:

    1) Архитектура, предложенная мной, потребует изменений во всех звеньях при добавлении компонентов C и D.
    2) Chain of Responsibility (в классическом виде) будет легче поддержать.

    Оба утверждения не соответствуют истине. Постараюсь это показать.

    Относительно 1.

    Есть 2 объекта:

    1) Хранитель обработчиков, который хранит объекты, как удобнее (в виде очереди, списка, массива, дерева и т.п.).
    2) Поисковик подходящего объекта, который ищет по заданному алгоритму (первый подходящий, последний подходящий или какому -либо другому правилу) в Хранителе.

    Сначала в Хранителе объектов 2 объекта: A и B. При необходимости, добавляем еще два — C и D. Помещаем их в нужное место (это можно сделать тоже при помощи конфигурационного файла), и вуаля! Где же проблема, о которой пишите Вы? Дополнительные объекты добавлять так же просто.

    Относительно 2.

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

    Chain of Responsibility имеет существенные ограничения на длину цепочки.
    С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re: Chain of responsibility
    От: konsoletyper Россия https://github.com/konsoletyper
    Дата: 04.09.06 15:27
    Оценка:
    Здравствуйте, Aviator, Вы писали:

    A>Пристально посмотрев на этот паттерн пришёл к выводу, что в нём чего то не хватает для законченности . Тпичная задача: есть набор компонент (классов), пердоставляющих некоторый набор сервисов. Соединяем всё это добро в оддно связанное приложение, в котором источниками и обработчиками запросов выступает этот набор компонент. И тут натыкаемся на проблему — во первых если один компонент инициирует некоторый запрос, вызывая при этом _nextComponent->Handle(aRequest), обраьотать запрос смогут только нижестоящие в списке компоненты... Далее, нередко требуется что бы обработать запрос мог только один компонент и при этом вернуть инициирующему запрос объекту результат... И на последок — в некоторых случаях компонент должен быть уверен, что созданный им запрос был получен всеми объектами в цепочке... Ну и напоследок — требуется средство формирование очереди, что бы некотрые объекты могли раньше получать сообщения... Вобщем по моему в классическом варианте от GoF много непоняток. Есть идеии как формализовать это всё хозяйство?


    Может, Mediator + Observer? Кстати, я даже Mediator + Observer + Chain of responsibility. Это дело умещается в библиотеке легковесных контролов. Все контролы располагаются не хосте, который в плане отрисовки и кэширования layout-а является медиатором. Контролы, принимающие ввод реализуют Observer (в дотнете он реализован на уровне языка). Ну а обработка клавиатуры производится при помощи Chain of responsibility — если контрол отказывается обрабатывать клавишу, то она перенаправляется его контейнеру. ИМХО, нужно уметь использовать простые паттерны в композиции, а не придумывать какие-то супер-мега-сложные паттерны.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[8]: Chain of responsibility
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 05.09.06 08:11
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>как поисковик узнаёт что объект подходит для обработки сообщения? приведите пример реализации и вы увидите что вощникнет проблема...


    Приведите Ваш пример, и я распишу, как это можно сделать... Если говорить о других примерах, то, например, в OWL поиск обработчика осуществляется таким образом:

    1. Сначала обработчик ищется в обработчиках контрола, который инициировал сообщение. Это на тот случай, когда программист хочет, чтобы кнопка САМА обрабатывала свое нажатие.
    2. Затем обработчик ищется в обработчиках окна, которому пришло сообщение. (Команды от контрола приходят родительскому окну.)
    3. Затем обработчик ищется в обработчиках родителя родителя и т.д.
    4. И, наконец, обработчик ищется в объекте приложения.

    Каждый объект, упомянутый в этом алгоритме, может быть объектом класса, который выведен из других классов. Соответственно, при поиске обработчика внутри объекта выполняется такой алгоритм:

    1) Ищем обработчик в таблице финального класса.
    2) Если не нашли, то ищем обработчик в таблицах базовых классов.
    3) И т.д. рекурсивно.

    Для поиска обработчика в таблицах используются 3 критерия:

    1) Идентификатор сообщения.
    2) Идентификатор команды, если сообщение WM_COMMAND или WM_NOTIFY.
    3) Идентификатор контрола, пославшего WM_COMMAND или WM_NOTIFY.

    Заметьте, в этой схеме реализована классическая Chain of Responsibility. Тем не менее, можно выделить критерии поиска:

    1. Место нахождения обработчика.
    2. Идентификатор сообщения, которое обрабатывает обработчик.
    3. Идентификаторы отправителя и/или предполагаемого получателя сообщения (откуда начинаем поиск).
    4. Дополнительные данные для обработки специализированных сообщений типа WM_COMMAND, WM_NOTIFY.

    Разумеется, для другого примера можно построить свой механизм.

    А>а если у вас будет здоровый класс, содержащий тысячи строк логики корму в каких случаях и когда что отсылать не запутаетесь ли вы что к чему и как поддерживать?


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

    А>Про ограничение на долину цепочки не согласен, не вижу серьёзной аргументации, разве что группировать наверно лучше в некоторую иерархическую структуру. Посмотрите архитектуру драйверов в windows — там как раз цепочка фильтров обработчиков... может не самый хороший пример но всё же.


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

    Можно хранить десяток и даже сотню объектов в массиве. Но для реализации реляционной базы данных, в которой содержатся миллионы записей, массив явно не подходит.
    С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re[9]: Chain of responsibility
    От: Аноним  
    Дата: 05.09.06 08:30
    Оценка:
    Здравствуйте, Кирилл Лебедев, Вы писали:

    КЛ>Здравствуйте, Аноним, Вы писали:


    А>>как поисковик узнаёт что объект подходит для обработки сообщения? приведите пример реализации и вы увидите что вощникнет проблема...


    КЛ>Приведите Ваш пример, и я распишу, как это можно сделать... Если говорить о других примерах, то, например, в OWL поиск обработчика осуществляется таким образом:


    КЛ>1. Сначала обработчик ищется в обработчиках контрола, который инициировал сообщение. Это на тот случай, когда программист хочет, чтобы кнопка САМА обрабатывала свое нажатие.

    КЛ>2. Затем обработчик ищется в обработчиках окна, которому пришло сообщение. (Команды от контрола приходят родительскому окну.)
    КЛ>3. Затем обработчик ищется в обработчиках родителя родителя и т.д.
    КЛ>4. И, наконец, обработчик ищется в объекте приложения.

    КЛ>Каждый объект, упомянутый в этом алгоритме, может быть объектом класса, который выведен из других классов. Соответственно, при поиске обработчика внутри объекта выполняется такой алгоритм:


    КЛ>1) Ищем обработчик в таблице финального класса.

    КЛ>2) Если не нашли, то ищем обработчик в таблицах базовых классов.
    КЛ>3) И т.д. рекурсивно.

    КЛ>Для поиска обработчика в таблицах используются 3 критерия:


    КЛ>1) Идентификатор сообщения.

    КЛ>2) Идентификатор команды, если сообщение WM_COMMAND или WM_NOTIFY.
    КЛ>3) Идентификатор контрола, пославшего WM_COMMAND или WM_NOTIFY.

    ага вот вы и сосредотачиваете в одномместе кучи логики кто за что отвечает, в классической цепи объект сам знает за что он отвечает

    КЛ>Разумеется, для другого примера можно построить свой механизм.


    А>>а если у вас будет здоровый класс, содержащий тысячи строк логики корму в каких случаях и когда что отсылать не запутаетесь ли вы что к чему и как поддерживать?


    КЛ>Наличие такого класса (который содержит "тысячи строк логики") свидетельствует о том, что класс спроектирован неверно. Скорее всего, этот класс выполняет кучу функций разного уровня сложности (да и вообще просто разных функций). Это уже, извините, помойка получается, а не класс.


    имеенно это вы и имеете в вашем лбимом MFC в виде карты сообщений... ужасный свитч по идетификаторам сообщений.
    Re[10]: Chain of responsibility
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 05.09.06 09:00
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>ага вот вы и сосредотачиваете в одномместе кучи логики кто за что отвечает, в классической цепи объект сам знает за что он отвечает


    Приведите Ваш пример, а там — посмотрим.

    А>имеенно это вы и имеете в вашем лбимом MFC в виде карты сообщений... ужасный свитч по идетификаторам сообщений.


    FYI: В картах сообщений в MFC и OWL не используется switch. К тому же, эти карты реализуют стандартную Chain of Responsibility.
    С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re[11]: Chain of responsibility
    От: Аноним  
    Дата: 05.09.06 09:55
    Оценка:
    Здравствуйте, Кирилл Лебедев, Вы писали:

    КЛ>Здравствуйте, Аноним, Вы писали:


    А>>ага вот вы и сосредотачиваете в одномместе кучи логики кто за что отвечает, в классической цепи объект сам знает за что он отвечает


    КЛ>Приведите Ваш пример, а там — посмотрим.


    А>>имеенно это вы и имеете в вашем лбимом MFC в виде карты сообщений... ужасный свитч по идетификаторам сообщений.


    КЛ>FYI: В картах сообщений в MFC и OWL не используется switch. К тому же, эти карты реализуют стандартную Chain of Responsibility.


    карта обработчиков в MFC предполагает чёткий критерий кто что обрабатывает.
    Re[12]: Chain of responsibility
    От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
    Дата: 05.09.06 10:02
    Оценка:
    Здравствуйте, <Аноним>, Вы писали:

    А>Здравствуйте, Кирилл Лебедев, Вы писали:


    КЛ>>Здравствуйте, Аноним, Вы писали:


    А>>>ага вот вы и сосредотачиваете в одномместе кучи логики кто за что отвечает, в классической цепи объект сам знает за что он отвечает


    КЛ>>Приведите Ваш пример, а там — посмотрим.


    А>>>имеенно это вы и имеете в вашем лбимом MFC в виде карты сообщений... ужасный свитч по идетификаторам сообщений.


    КЛ>>FYI: В картах сообщений в MFC и OWL не используется switch. К тому же, эти карты реализуют стандартную Chain of Responsibility.


    А>карта обработчиков в MFC предполагает чёткий критерий кто что обрабатывает.


    Я извиняюсь, что пишу ответ на Ваш пост, но мои ответы грустно игнорируются

    К теме о проблемах использования механизма поиска, основанного на критериях
    Автор: pt4h
    Дата: 04.09.06
    и Chain of Responsibility.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[12]: Chain of responsibility
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 05.09.06 11:01
    Оценка:
    Здравствуйте, Аноним, Вы писали:

    А>карта обработчиков в MFC предполагает чёткий критерий кто что обрабатывает.


    И? Поэтому-то и нужен пример.
    С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re[6]: Chain of responsibility
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 05.09.06 11:15
    Оценка:
    Здравствуйте, pt4h, Вы писали:

    P>
  • Если набор данных, которые необходимо заполнять изменяется, изменения придется вносить во все обработчики.

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

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

    Опять-таки ошибка. Если мы представляем обработчики в виде Chain of Responsibility, значит мы смотрим на них с одинаковой точки зрения. Следовательно, и критерии можно подобрать сразу для всех обработчиков, т.к. эти критерии основываются на общей точке зрения. Т.е., грубо говоря, при группировке важны не внутренние различия самих обработчиков, а общая точка зрения, с которой мы эти обработчики рассматриваем. (Эта мысль сложна. Поэтому я рекомендую ее прочитать еще раз. В ней есть смысл.)

    P>
  • Если критерии не могу быть представлены в виде выделнных данных, а являются скажем результатом выполнения какого-то алгоритма в момент обработки данных — поиск по критерию тоже не будет работать.
    P>
  • Количество структур поиска будет расти вместе с количеством событий.

    Мне кажется, что Ваша аргументация стала чисто умозрительной. Ей не хватает конкретных примеров. Приведите пример — тогда мы посмотрим. А так, чисто умозрительно, можно долго строить разные предположения. Это ничего не докажет.
  • С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re[7]: Chain of responsibility
    От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
    Дата: 05.09.06 11:35
    Оценка:
    Здравствуйте, Кирилл Лебедев, Вы писали:

    Step-by-step.

    КЛ>Здравствуйте, pt4h, Вы писали:


    P>>
  • Если набор данных, которые необходимо заполнять изменяется, изменения придется вносить во все обработчики.

    КЛ>Вовсе нет. Дополнительно введенные критерии можно игнорировать и использовать значения по умолчанию.


    Это значит, что мы можем не найти новые обработчики.

    КЛ>Кроме того, классификационные критерии изменяются гораздо реже, чем объекты, которые они классифицируют.


    Как раз наооборот. Обработчики первичны, а критерии вторичны.


    Соответственно, обработчик не должен выставлять никаких данных.

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

    КЛ>Опять-таки ошибка. Если мы представляем обработчики в виде Chain of Responsibility, значит мы смотрим на них с одинаковой точки зрения.


    Неправильно. С точки зрения паттерна

    Handler (HelpHandler) — обработчик:
    — определяет интерфейс для обработки запросов;
    — (необязательно) реализует связь с преемником;


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

    КЛ>Следовательно, и критерии можно подобрать сразу для всех обработчиков, т.к. эти критерии основываются на общей точке зрения.


    Опять неправильно. Смотри пункт выше.

    КЛ>Т.е., грубо говоря, при группировке важны не внутренние различия самих обработчиков, а общая точка зрения, с которой мы эти обработчики рассматриваем.


    КЛ>(Эта мысль сложна. Поэтому я рекомендую ее прочитать еще раз. В ней есть смысл.)


    Читал не один раз.

    P>>
  • Если критерии не могу быть представлены в виде выделнных данных, а являются скажем результатом выполнения какого-то алгоритма в момент обработки данных — поиск по критерию тоже не будет работать.
    P>>
  • Количество структур поиска будет расти вместе с количеством событий.

    КЛ>Мне кажется, что Ваша аргументация стала чисто умозрительной. Ей не хватает конкретных примеров. Приведите пример — тогда мы посмотрим. А так, чисто умозрительно, можно долго строить разные предположения. Это ничего не докажет.


    Без проблем.

    Обработчик 1 — могу обработать, если сегодня 5-ое сентября.
    Обработчик 2 — могу обработать, если Гитлер умер.
    Обработчик 3 — могу обработать, если у меня нет следующего обработчика.
    .....
    Обработчик N — могу обработать, если все обработчики до меня не смогли обработать.

    Представление данных обработчиков по схеме критериев приведет к созданию схемы критериев с N записями.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
  • Re[8]: Chain of responsibility
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 05.09.06 21:07
    Оценка:
    Здравствуйте, pt4h, Вы писали:

    P>Обработчик 1 — могу обработать, если сегодня 5-ое сентября.

    P>Обработчик 2 — могу обработать, если Гитлер умер.
    P>Обработчик 3 — могу обработать, если у меня нет следующего обработчика.
    P>.....
    P>Обработчик N — могу обработать, если все обработчики до меня не смогли обработать.

    P>Представление данных обработчиков по схеме критериев приведет к созданию схемы критериев с N записями.


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


    Шаг 0. Применим паттерн Chain of Responsibility в классическом виде.


    Заведем базовый класс THandler для обработчиков цепочки:

    class TMessage {...};
    
    class THandler
    {
    public:
    
       virtual ~THandler();
       virtual void HandleMessage(const TMessage & rMessage)= 0;
    };


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

    1) Проверяет, может ли данный обработчик обработать сообщение самостоятельно.
    2) Если может, то обрабатывает его.
    3) Если нет, то ищет другой обработчик и передает управление ему.

    Для того чтобы отправить сообщение на обработку, вызывающий код должен вызвать HandleMessage для начала цепочки:

    THandler * pHead;
    //...
    pHead->HandleMessage(message);



    Шаг 1. Выделим каждую операцию в отдельную функцию.


    У нас останется все та же Chain of Responsibility. Только класс THandler будет иметь три функции:

    class THandler
    {
    public:
    
       virtual ~THandler();
       virtual bool CanHandle(const TMessage & rMessage) const = 0;
       virtual THandler * GetNextHandler() const = 0;
       virtual void HandleMessage(const TMessage & rMessage)= 0;
    };


    Вызывающий код будет состоять из двух этапов:

    1) Сначала ищем подходящий обработчик.
    2) Если находим, то вызываем его для обработки сообщения.

    THandler * SearchHandler(THandler * pHandler, const TMessage & rMessage)
    {
       assert(pHandler != NULL);
    
       while (pHandler && !pHandler->CanHandle(rMessage))
          pHandler = pHandler->GetNextHandler();
    
       return pHandler;
    }
    
    THandler * pHandler = SearchHandler(pHead, rMessage);
    
    if (pHandler)
       pHandler->HandleMessage(rMessage);


    Что это дает?

    1) Мы всегда можем определить, обработали мы сообщение или нет. И, при желании, получить результат обработки, т.е. четко понять: или это обработка закончилась таким результатом, или это мы не нашли обработчика.
    2) Исходный код получается более структурированным. Т.к. мы отделили функцию обработки сообщения от функции поиска обработчика. Раньше у нас все было смешано в одной функции. Теперь – разделено. Собственно, это азы структурного программирования.

    Я мог бы остановиться на этом решении, т.к. оно соответствует тому, что я говорил раньше, и полностью опровергает Ваши сомнения. Но считаю правильным двигаться дальше.


    Шаг 2. Вынесем проверку условия за пределы обработчика.


    Иными словами, будем проверять, может ли данный handler обработать данное сообщение, не в самом handler’е, а в специально организованном (например, в виде набора правил) коде.

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


    1) Если поступило сообщение А, и сегодня 5 сентября, то заменяем сообщение А на сообщение Ы.
    2) Если поступило сообщение Б, и умер Гитлер, то заменяем сообщение Б на сообщение Й.
    3) И т.д.


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

    1) Причины 1 – 2 из шага 1.
    2) Можно менять правила, не меняя обработчика. Благодаря этому достигается гибкость.
    3) Обработчики можно сгруппировать в какую-нибудь простую структуру данных, например, в std::map или хэш-таблицу, а всю логику – вынести в набор правил для поиска, который можно редактировать в файле, не прибегая к перекомпиляции кода.
    4) На большой статистике, т.е. когда у нас наберется достаточное количество правил, будет виден способ их возможного сжатия (свертывания). Если же мы используем обычную Chain of Responsibility, то правила разбросаны по коду (по элементам цепочки). Поэтому сжать их не представляется возможным. Как следствие, код растет, и его все труднее и труднее сопровождать.
    С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re[5]: Chain of responsibility
    От: Sinclair Россия https://github.com/evilguest/
    Дата: 06.09.06 05:01
    Оценка:
    Здравствуйте, <Аноним>, Вы писали:
    А>не в этом задача нужно что бы никакой компонент в цепочке для некоторых сообщений не имел возможности прервать обработку, отказавшись вызвать next->Handle(theRequest)
    В таком случае достаточно засунуть логику вызова следующего обработчика в невиртуальный метод базового класса и заставить всех обработчиков наследоваться от него:
    public abstract class HandlerBase<TRequest>:IHandler<TRequest>
    {
      private HandlerBase<TRequest> _next;
      protected HandlerBase(HandlerBase<TRequest> next) // следующим будет только такой же HandlerBase.
        {
            _next = next;
        }
      void IHandler<TRequest>.Handle(TRequest request)
        {
          try
            {
            HandleLocally(request);
            }
            finally// гарантируем невозможность прервать обработку выбросом исключения
            {
                // теперь дадим следующему шанс выкинуть свое исключение:
                if (_next != null) 
                    _next.Handle();
            }
        }
        
        protected abstract void HandleLocally(TRequest request); // только этот метод можно перекрывать
    }
    1.1.4 stable rev. 510
    Уйдемте отсюда, Румата! У вас слишком богатые погреба.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.