Здравствуйте, Аноним, Вы писали:
А>ага вот вы и сосредотачиваете в одномместе кучи логики кто за что отвечает, в классической цепи объект сам знает за что он отвечает
Приведите Ваш пример, а там — посмотрим.
А>имеенно это вы и имеете в вашем лбимом MFC в виде карты сообщений... ужасный свитч по идетификаторам сообщений.
FYI: В картах сообщений в MFC и OWL не используется switch. К тому же, эти карты реализуют стандартную Chain of Responsibility.
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Здравствуйте, Аноним, Вы писали:
А>>ага вот вы и сосредотачиваете в одномместе кучи логики кто за что отвечает, в классической цепи объект сам знает за что он отвечает
КЛ>Приведите Ваш пример, а там — посмотрим.
А>>имеенно это вы и имеете в вашем лбимом MFC в виде карты сообщений... ужасный свитч по идетификаторам сообщений.
КЛ>FYI: В картах сообщений в MFC и OWL не используется switch. К тому же, эти карты реализуют стандартную Chain of Responsibility.
карта обработчиков в MFC предполагает чёткий критерий кто что обрабатывает.
Здравствуйте, <Аноним>, Вы писали:
А>Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>>Здравствуйте, Аноним, Вы писали:
А>>>ага вот вы и сосредотачиваете в одномместе кучи логики кто за что отвечает, в классической цепи объект сам знает за что он отвечает
КЛ>>Приведите Ваш пример, а там — посмотрим.
А>>>имеенно это вы и имеете в вашем лбимом MFC в виде карты сообщений... ужасный свитч по идетификаторам сообщений.
КЛ>>FYI: В картах сообщений в MFC и OWL не используется switch. К тому же, эти карты реализуют стандартную Chain of Responsibility.
А>карта обработчиков в MFC предполагает чёткий критерий кто что обрабатывает.
Я извиняюсь, что пишу ответ на Ваш пост, но мои ответы грустно игнорируются
Здравствуйте, pt4h, Вы писали:
P>Если набор данных, которые необходимо заполнять изменяется, изменения придется вносить во все обработчики.
Вовсе нет. Дополнительно введенные критерии можно игнорировать и использовать значения по умолчанию.
Кроме того, классификационные критерии изменяются гораздо реже, чем объекты, которые они классифицируют.
P>Так как мы не привязываемся к обработчику, то каждый из них может быт исключительно уникальным и соответственно данные и критерии могут быть абсолютно разными. В итоге эта структура соберет в себя все возможные критерии.
Опять-таки ошибка. Если мы представляем обработчики в виде Chain of Responsibility, значит мы смотрим на них с одинаковой точки зрения. Следовательно, и критерии можно подобрать сразу для всех обработчиков, т.к. эти критерии основываются на общей точке зрения. Т.е., грубо говоря, при группировке важны не внутренние различия самих обработчиков, а общая точка зрения, с которой мы эти обработчики рассматриваем. (Эта мысль сложна. Поэтому я рекомендую ее прочитать еще раз. В ней есть смысл.)
P>Если критерии не могу быть представлены в виде выделнных данных, а являются скажем результатом выполнения какого-то алгоритма в момент обработки данных — поиск по критерию тоже не будет работать. P>Количество структур поиска будет расти вместе с количеством событий.
Мне кажется, что Ваша аргументация стала чисто умозрительной. Ей не хватает конкретных примеров. Приведите пример — тогда мы посмотрим. А так, чисто умозрительно, можно долго строить разные предположения. Это ничего не докажет.
Step-by-step.
КЛ>Здравствуйте, pt4h, Вы писали:
P>>Если набор данных, которые необходимо заполнять изменяется, изменения придется вносить во все обработчики.
КЛ>Вовсе нет. Дополнительно введенные критерии можно игнорировать и использовать значения по умолчанию.
Это значит, что мы можем не найти новые обработчики.
КЛ>Кроме того, классификационные критерии изменяются гораздо реже, чем объекты, которые они классифицируют.
Как раз наооборот. Обработчики первичны, а критерии вторичны.
Соответственно, обработчик не должен выставлять никаких данных.
P>>Так как мы не привязываемся к обработчику, то каждый из них может быт исключительно уникальным и соответственно данные и критерии могут быть абсолютно разными. В итоге эта структура соберет в себя все возможные критерии.
КЛ>Опять-таки ошибка. Если мы представляем обработчики в виде Chain of Responsibility, значит мы смотрим на них с одинаковой точки зрения.
Неправильно. С точки зрения паттерна
Handler (HelpHandler) — обработчик:
— определяет интерфейс для обработки запросов;
— (необязательно) реализует связь с преемником;
Мы на них смотрим одинаково лишь с той точки зрения, что они могут обработать запрос.
КЛ>Следовательно, и критерии можно подобрать сразу для всех обработчиков, т.к. эти критерии основываются на общей точке зрения.
Опять неправильно. Смотри пункт выше.
КЛ>Т.е., грубо говоря, при группировке важны не внутренние различия самих обработчиков, а общая точка зрения, с которой мы эти обработчики рассматриваем.
КЛ>(Эта мысль сложна. Поэтому я рекомендую ее прочитать еще раз. В ней есть смысл.)
Читал не один раз.
P>>Если критерии не могу быть представлены в виде выделнных данных, а являются скажем результатом выполнения какого-то алгоритма в момент обработки данных — поиск по критерию тоже не будет работать. P>>Количество структур поиска будет расти вместе с количеством событий.
КЛ>Мне кажется, что Ваша аргументация стала чисто умозрительной. Ей не хватает конкретных примеров. Приведите пример — тогда мы посмотрим. А так, чисто умозрительно, можно долго строить разные предположения. Это ничего не докажет.
Без проблем.
Обработчик 1 — могу обработать, если сегодня 5-ое сентября.
Обработчик 2 — могу обработать, если Гитлер умер.
Обработчик 3 — могу обработать, если у меня нет следующего обработчика.
.....
Обработчик N — могу обработать, если все обработчики до меня не смогли обработать.
Представление данных обработчиков по схеме критериев приведет к созданию схемы критериев с N записями.
Здравствуйте, 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 для начала цепочки:
1) Мы всегда можем определить, обработали мы сообщение или нет. И, при желании, получить результат обработки, т.е. четко понять: или это обработка закончилась таким результатом, или это мы не нашли обработчика.
2) Исходный код получается более структурированным. Т.к. мы отделили функцию обработки сообщения от функции поиска обработчика. Раньше у нас все было смешано в одной функции. Теперь – разделено. Собственно, это азы структурного программирования.
Я мог бы остановиться на этом решении, т.к. оно соответствует тому, что я говорил раньше, и полностью опровергает Ваши сомнения. Но считаю правильным двигаться дальше.
Шаг 2. Вынесем проверку условия за пределы обработчика.
Иными словами, будем проверять, может ли данный handler обработать данное сообщение, не в самом handler’е, а в специально организованном (например, в виде набора правил) коде.
Каждое правило в этом наборе работает как фильтр для почтовой программы, т.е. проверяет наличие определенного условия и модифицирует исходное сообщение. Например:
1) Если поступило сообщение А, и сегодня 5 сентября, то заменяем сообщение А на сообщение Ы.
2) Если поступило сообщение Б, и умер Гитлер, то заменяем сообщение Б на сообщение Й.
3) И т.д.
При помощи таких фильтров мы заменяем сложные комплексные условия для вызова того или иного обработчика на простое условие. Это полезно по следующим причинам:
1) Причины 1 – 2 из шага 1.
2) Можно менять правила, не меняя обработчика. Благодаря этому достигается гибкость.
3) Обработчики можно сгруппировать в какую-нибудь простую структуру данных, например, в std::map или хэш-таблицу, а всю логику – вынести в набор правил для поиска, который можно редактировать в файле, не прибегая к перекомпиляции кода.
4) На большой статистике, т.е. когда у нас наберется достаточное количество правил, будет виден способ их возможного сжатия (свертывания). Если же мы используем обычную Chain of Responsibility, то правила разбросаны по коду (по элементам цепочки). Поэтому сжать их не представляется возможным. Как следствие, код растет, и его все труднее и труднее сопровождать.
Здравствуйте, <Аноним>, Вы писали: А>не в этом задача нужно что бы никакой компонент в цепочке для некоторых сообщений не имел возможности прервать обработку, отказавшись вызвать 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
Уйдемте отсюда, Румата! У вас слишком богатые погреба.