Подскажите, пожалуйста:
как правильно делается передача лога (протокола, журнала) о выполняемых действиях в подчиненных модулях на вышестоящий (вызывающий) уровень?
Есть программа обмена с кассами.
Главная форма отображает:
— таблицу касс с тремя колонками: флажок выбора кассы для выполнения операции, название кассы, результат последнего обмена;
— две кнопки: "Выгрузить" и "Загрузить".
После нажатия на кнопку и выполнения обмена (загрузки или выгрузки) в колонке "Результат" для соответствующей кассы должно быть написано типа "Успех" или "Ошибка".
Чтобы узнать подробнее, что происходило при обмене, можно щелкнуть на поле "Результат" и открывается дополнительная форма, в которой отображается более подробная информация обо всех действиях с кассой в виде списка текстовых строк типа журнала (или лога).
Пока для простоты журнал представляет собой просто массив строк.
Например:
— "В настройках кассы не указан каталог обмена"
— "Отсутствует каталог обмена"
— "Ошибка записи данных в файл obmen.txt"
— "Не выполнен обмен с кассой Касса5"
Проблема в том, что обработка обмена реализована несколькими классами, которые вызывают друг друга.
Я разбил все классы на уровни, основные уровни: UI, Бизнес-логика, Обмен с кассой в конкретном формате.
И получилась большая "глубина" вызовов.
Например:
класс "Главная форма" -> презентер -> контроллер "Обработка списка касс" — > класс бизнес-логики "Операция с кассой" -> класс "Обмен в формате ХХХ" -> Работа с файловой системой и т. д.
То есть самый "глубокий" класс ничего не знает о самом верхнем классе (о Главной форме), в который надо передать лог-журнал.
Кроме того, при работе "внутренних" классов и модулей могут возникать исключения.
Эти исключения должны перехватываться, и также записываться в этот "вышестоящий" журнал.
А также, чисто теоретически, все это может выполняться в многопоточном режиме и причем с разных рабочих мест.
Как это делается?
Самое простое — это передавать объект ResultArray в качестве параметра во все вызываемые методы.
Но это очень не удобно.
Так как например модуль "Обмена в формате ХХХ" уже написан, менять все методы неохота.
А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.
Здравствуйте, es3000, Вы писали:
E>Проблема в том, что обработка обмена реализована несколькими классами, которые вызывают друг друга. E>Я разбил все классы на уровни, основные уровни: UI, Бизнес-логика, Обмен с кассой в конкретном формате. E>И получилась большая "глубина" вызовов. E>Например: E>класс "Главная форма" -> презентер -> контроллер "Обработка списка касс" — > класс бизнес-логики "Операция с кассой" -> класс "Обмен в формате ХХХ" -> Работа с файловой системой и т. д. E>То есть самый "глубокий" класс ничего не знает о самом верхнем классе (о Главной форме), в который надо передать лог-журнал.
Что делает каждый из этих классов в цепочке? Для чего они нужны, каковы их обязанности?
Что они принимают на вход и какой результат возвращают?
E>Кроме того, при работе "внутренних" классов и модулей могут возникать исключения. E>Эти исключения должны перехватываться, и также записываться в этот "вышестоящий" журнал. E>А также, чисто теоретически, все это может выполняться в многопоточном режиме и причем с разных рабочих мест.
Исключения — обрабатывать. Для многопоточного режима — создать особый, МногопоточныйЖурнал (реализация IЖурнал, см. ниже)
E>Как это делается?
"Обмен в формате ХХХ" в любом случае должен вернуть статус операции ("Успех/Отказ")
Что касается журнала, то два варианта:
Можно договориться, что при вызове "Обмен в формате ХХХ" должен возвращать журнал (список строк) наряду со статусом операции
Можно наоборот передать класс Журнала (реализация IЖурнал) в класс "Обмен в формате ХХХ" и договориться, что если понадобится куда-то что-то вывести, то он будет использовать переданный журнал. Затем сделать ФайлЖурнал, который реализовывает IЖурнал, если нужно вести журнал в файле. Или сделать ПамятьЖурнал, который реализовывает IЖурнал, если нужно вести журнал в массиве строк. А может ОблакоЖурнал, который хранит журнал в облаке.
Таким образом у тебя уйдет зависимость "Обмен в формате ХХХ" от файловой системы. С другой стороны, ты сможет работать хоть с файлами, хоть с облаком, хоть с памятью.
E>Самое простое — это передавать объект ResultArray в качестве параметра во все вызываемые методы. E>Но это очень не удобно. E>Так как например модуль "Обмена в формате ХХХ" уже написан, менять все методы неохота.
Достаточно вывод в файл заменить на вывод в IЖурнал.
E>А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.
О классах знать не должен, а о простых интерфейсах — может.
Best regards, Буравчик
Re[2]: Передача лога о выполняемых действиях из подчиненного
Б>Что делает каждый из этих классов в цепочке? Для чего они нужны, каковы их обязанности? Б>Что они принимают на вход и какой результат возвращают?
Главная форма:
— таблица строк с колонками "Флажок, Касса, Результат выгрузки, Результат загрузки"
— Кнопки "Выгрузить", "Загрузить"
— по событиям от кнопок вызывает методы Презентера "ЗагрузитьДанные" и "ВыгрузитьДанные"
— при щелчке на колонке "Результат" таблице вызывает метод Презентера "Подробности"
Презентер — логика интерфейса — обрабатывает события от контролов формы
— Методы "ЗагрузитьДанные" и "ВыгрузитьДанные": создают список отмеченных касс и передают этот список методам Контролера с тем же названием
— Метод "КассаОбработана", который вызывается из Контроллера обновляет поля таблицы на форме (результат) для конкретной кассы
— Метод "Подробности": получает от Контроллера последнюю операцию с кассой и открывает форму "Подробный результат"
Контроллер "Обработка списка касс"
— Входные данные: список отмеченных касс
— подписка на событие "Касса обработана" Сценария
— При срабатывании события получает кассу, ее результат и отправляет Презентеру методу "КассаОбработана"
— При запросе от Презентера возращает ему последнюю операцию с кассой
Класс БЛ "Сценарий обработки касс по списку"
— хранит обработанных список касс
— хранит для каждой кассы последнюю выполненную операцию
— Метод "ОбработатьКассы":
— в цикле для каждой кассы проверяет настройки кассы
— создает экземпляр "Операции с кассой", вызывает его метод "Выполнить"
— вызывает подписчик на событие "КассаОбработана" с передачей параметров — Касса, Операция
Класс БЛ "Операция с кассой" (базовый):
— хранит Результат (в зависимости от операции есть дополнительные реквизиты у результата)
Класс БЛ "Выгрузка в кассу" — наследник "Операция с кассой""
— реализуют конкретную операцию — выгрузка (или загрузка)
— извлекает данные из БД
— вызывает методы класса "Обмен в формате ХХХ"
— сохраняет результат ("Успех" или "Ошибка")
— устанавливает дополнительные поля результата (количество всех товаров, итоговая сумма)
Класс "Обмен в формате ХХХ":
— знает какие файлы надо читать\записывать и в каком формате
— записывает \ читает даные
— конвертирует эти данные между форматом Бизнес-логики и форматом ХХХ
Журнал должен отображаться Презентером.
В этот Журнал должны попасть все сообщения о выполняемых действиях из нижележащих классов.
Например, в классе "Обмен в формате ХХХ" может быть такое сообщение:
Журнал.Отладка("Записываю файл kassa1.txt");
Журнал.Отладка("Файл kassa1.txt записан успешно");
Перехват всех исключений будет выполнен в методе "Сценарий.ОбработатьКассы" и второй раз в методе "Презентер.КассаОбработана".
Как протащить ссылку на Журнал с самого верха до самого низа?
Б>"Обмен в формате ХХХ" в любом случае должен вернуть статус операции ("Успех/Отказ")
Б>Что касается журнала, то два варианта: Б>Можно договориться, что при вызове "Обмен в формате ХХХ" должен возвращать журнал (список строк) наряду со статусом операции
В этот журнал должен писать не только "Обмен в формате ХХХ", но и вышестоящие классы.
Так как логика конкретной операции определяется вышестоящими классами.
Б>Можно наоборот передать класс Журнала (реализация IЖурнал) в класс "Обмен в формате ХХХ" и договориться, что если понадобится куда-то что-то вывести, то он будет использовать переданный журнал.
Да, наверно лучше через интерфейс.
Тогда, получается, что этот интерфейс надо устанавливать для всех объектов, которые пишут в этот журнал.
В конструкторах у всех объектов бизнес-слоя надо передавать журнал?
Получается, весь бизнес-слой "завязан" на журнал. Это же плохо?
Б>Таким образом у тебя уйдет зависимость "Обмен в формате ХХХ" от файловой системы. С другой стороны, ты сможет работать хоть с файлами, хоть с облаком, хоть с памятью.
Зависимость от файловой системы — я имел ввиду другую.
Я имел ввиду не запись в файл журнала.
Я имел ввиду, что этот класс "знает" как работать с файловой системой (открытие\чтение\запись\закрытие файлов), чтобы записать файлы обмена с кассой.
E>А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей. Б>О классах знать не должен, а о простых интерфейсах — может.
То есть и сюда через конструктор передавать IЖурнал?
Но ведь модуль файловой системы работает не только с подсистемой обмена с кассами.
Одна и а же функция этого модуля, например "WriteFile()" может вызываться для обмена с кассами (и должна писать в IЖурнал).
А может вызываться и для других целей из других модулей программы — и в этом случае она также пишет в некий журнал, но эти записи не должны попасть в Журнал обработки кассы, но должны попасть например в системный журнал.
Re: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, es3000, Вы писали:
E>Самое простое — это передавать объект ResultArray в качестве параметра во все вызываемые методы. E>Но это очень не удобно.
Зато это позволит легко собрать вместе все логи, относящиеся к конкретному запросу. И не искать их потом по всему лог-файлу. Кроме того, можно вообще не сохранять детальный лог, в случае успешного выполнения запроса. А вот в случае ошибки детали не помешают.
E>Так как например модуль "Обмена в формате ХХХ" уже написан, менять все методы неохота. E>А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.
А ты назови этот объект как-нибудь нейтрально, например, Context. И не считай его "специальным классом вышестоящих модулей", а считай его всехним классом.
Re[2]: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, Pzz, Вы писали: Pzz>А ты назови этот объект как-нибудь нейтрально, например, Context. И не считай его "специальным классом вышестоящих модулей", а считай его всехним классом.
Даже если мы соглашаемся на такую громоздкость, как передача контекста во все методы, есть специальные случаи — конструкторы и деструкторы, из которых запись в лог очень даже может понадобиться.
Могут быть также переопределенные методы классов из сторонних библиотек, где сигнатура не предусматривает передачу пользовательских параметров.
Я бы для таких задач как лог сделал синглетон Environment.
В нем и сделать различные глобальные флаги, лог и т.п. вспомогательные сервисы.
Для юнит тестов можно создавать какой-то специальный Environment, который вместо log-файла пишет в предоставленный тестом контейнер.
Re[3]: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, qaz77, Вы писали:
Q>Даже если мы соглашаемся на такую громоздкость, как передача контекста во все методы, есть специальные случаи — конструкторы и деструкторы, из которых запись в лог очень даже может понадобиться.
По мне, так лучше бы в пути каждого отдельного запроса не было бы конструкторов и деструкторов сколь-либо нетривиальных объектов — это плохо с точки зрения производительности. Лучше сначала сконструировать всю инфраструктуру, а потом гнать по ней запросы стройными рядами.
Q>Могут быть также переопределенные методы классов из сторонних библиотек, где сигнатура не предусматривает передачу пользовательских параметров.
Они могут и логи не уметь писать (или собирать их в приемломом виде). Вероятно, для таких классов уместнее было бы логировать до/после обращений к ним.
Q>Я бы для таких задач как лог сделал синглетон Environment. Q>В нем и сделать различные глобальные флаги, лог и т.п. вспомогательные сервисы.
Если в системе обрабатывается одновременно 100500 запросов, а все логи сыпятся в Environment, то потом будет трудно сводить вместе логи, относящиеся к одному запросу.
Такой синглетон было бы уместно иметь в качестве финального места, куда все логи отправляются. Пусть он думает, в какой директории их хранить, в зависимости от операционной системы и пользовательских предпочтений, как ротировать и т.п.
Re[3]: Передача лога о выполняемых действиях из подчиненного уровня
Q>Я бы для таких задач как лог сделал синглетон Environment. Q>В нем и сделать различные глобальные флаги, лог и т.п. вспомогательные сервисы. Q>Для юнит тестов можно создавать какой-то специальный Environment, который вместо log-файла пишет в предоставленный тестом контейнер.
Но тогда в этот Environment.Log будут писать все и всё.
Как в Форме обмена я смогу получить из этого лога только те записи, которые имеют отношение к последнему обмену с конкретной кассой?
Re[4]: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, es3000, Вы писали: Q>>Я бы для таких задач как лог сделал синглетон Environment. Q>>В нем и сделать различные глобальные флаги, лог и т.п. вспомогательные сервисы. Q>>Для юнит тестов можно создавать какой-то специальный Environment, который вместо log-файла пишет в предоставленный тестом контейнер.
E>Но тогда в этот Environment.Log будут писать все и всё.
В большинстве случаев такой подход работает.
Я же не знаю специфики твоей задачи...
E>Как в Форме обмена я смогу получить из этого лога только те записи, которые имеют отношение к последнему обмену с конкретной кассой?
Если в логи пишется id кассы, то выбрать по нему?
Или сделать раздельные логи на уровне абстракции кассы (раз уж это ее персональный лог).
Re[4]: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, Pzz, Вы писали:
Q>>Могут быть также переопределенные методы классов из сторонних библиотек, где сигнатура не предусматривает передачу пользовательских параметров.
Pzz>Они могут и логи не уметь писать (или собирать их в приемломом виде). Вероятно, для таких классов уместнее было бы логировать до/после обращений к ним.
Не совсем понятно, как можно вклиниться до/после вызова, если это уже callback, который дергает сторонняя либа.
Например, используем сторонний XML SAX парсер.
Он дергает callback, какой-нибудь OnBeginElement(name), т.е. наш код, который что-то из xml читает.
Как нам достучаться до лога из такого callback?
Re[5]: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, qaz77, Вы писали:
Q>Например, используем сторонний XML SAX парсер. Q>Он дергает callback, какой-нибудь OnBeginElement(name), т.е. наш код, который что-то из xml читает. Q>Как нам достучаться до лога из такого callback?
Там разве нельзя этому каллбеку void pointer передать в качестве контекста?
Но вообще, я не уверен, что надо каждый вызов каллбека из XML-парсера логировать. Казалось бы, достаточно залогировать сам факт, удалось ли распарсить XML, построить из него какой-то DOM, проверить его корректность, и результат этой проверки тоже залогировать. Ну еще в случае проблем можно сам сырой XML в логе сохранить, если он не необъятного размера.
Re[6]: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, Pzz, Вы писали: Pzz>Там разве нельзя этому каллбеку void pointer передать в качестве контекста?
Pzz>Но вообще, я не уверен, что надо каждый вызов каллбека из XML-парсера логировать. Казалось бы, достаточно залогировать сам факт, удалось ли распарсить XML, построить из него какой-то DOM, проверить его корректность, и результат этой проверки тоже залогировать. Ну еще в случае проблем можно сам сырой XML в логе сохранить, если он не необъятного размера.
Я же не про конкретный парсер или специфику xml...
Это только в качестве иллюстрации.
Мало ли библиотек, где в callback нет пользовательских параметров.
Я к тому, что не стоит загонять себя в угол проектным решением, пытаясь везде передавать контекст явно.
Особенно, когда это такая вспомогательно-отладочная штука как лог.
Можно взглянуть на передачу контекста под другим углом.
Т.к. контекст передается во все функции, то можно сделать их методами контекста, а соответствующий параметр убрать.
Получится такой God-object, в котором сосредоточен весь зависимый от логов функционал.
В общем, дурь получается...
Re[5]: Передача лога о выполняемых действиях из подчиненного уровня
Q>>>Я бы для таких задач как лог сделал синглетон Environment. E>>Но тогда в этот Environment.Log будут писать все и всё.
Q>В большинстве случаев такой подход работает. Q>Я же не знаю специфики твоей задачи...
Я задачу практически уже полностью расписал.
У меня уже есть такой "глобальный" лог — он пишет все сообщения в файл.
А для операций с кассой нужен дополнительный Журнал, в котором только операции с кассой.
Re[7]: Передача лога о выполняемых действиях из подчиненного
Q>Я к тому, что не стоит загонять себя в угол проектным решением, пытаясь везде передавать контекст явно. Q>Особенно, когда это такая вспомогательно-отладочная штука как лог.
Q>В общем, дурь получается...
Точно.
Вот я и ломаю голову. Не хочется дурь делать.
Здравствуйте, es3000, Вы писали:
E>В этот журнал должен писать не только "Обмен в формате ХХХ", но и вышестоящие классы. E>Так как логика конкретной операции определяется вышестоящими классами.
Передай и другим классам этот журнал.
Либо тот же самый экземпляр (если надо писать в этот же журнал), либо новый экземпляр (если у каждого свой журнал)
E>В конструкторах у всех объектов бизнес-слоя надо передавать журнал?
Да
E>Получается, весь бизнес-слой "завязан" на журнал. Это же плохо?
Не плохо. Лучше зависеть от абстрактного журнала, а не, например, от "журнала на файлах".
E>Зависимость от файловой системы — я имел ввиду другую. E>Я имел ввиду не запись в файл журнала. E>Я имел ввиду, что этот класс "знает" как работать с файловой системой (открытие\чтение\запись\закрытие файлов), чтобы записать файлы обмена с кассой.
Ну вот, теперь от файлов будут зависеть только те, кому нужны файлы, например "журнал в файле" или "обмен ХХХ с помощью файлов".
E>То есть и сюда через конструктор передавать IЖурнал? E>Но ведь модуль файловой системы работает не только с подсистемой обмена с кассами. E>Одна и а же функция этого модуля, например "WriteFile()" может вызываться для обмена с кассами (и должна писать в IЖурнал). E>А может вызываться и для других целей из других модулей программы — и в этом случае она также пишет в некий журнал, но эти записи не должны попасть в Журнал обработки кассы, но должны попасть например в системный журнал.
Ты точно уверен, что WriteFile должен писать в журнал?
В первом случае передай ему MemoryJournal: IJournal, который будет писать в массив строк, которые ты позже будешь использовать в свой форме
А во втором случае SystemJournal: IJournal, который будет писать в системный журнал
Best regards, Буравчик
Re[3]: Передача лога о выполняемых действиях из подчиненного
Б>>Что делает каждый из этих классов в цепочке? Для чего они нужны, каковы их обязанности? Б>>Что они принимают на вход и какой результат возвращают?
E>Главная форма: E> — таблица строк с колонками "Флажок, Касса, Результат выгрузки, Результат загрузки" E> — Кнопки "Выгрузить", "Загрузить" E> — по событиям от кнопок вызывает методы Презентера "ЗагрузитьДанные" и "ВыгрузитьДанные" E> — при щелчке на колонке "Результат" таблице вызывает метод Презентера "Подробности" E>Презентер — логика интерфейса — обрабатывает события от контролов формы E> — Методы "ЗагрузитьДанные" и "ВыгрузитьДанные": создают список отмеченных касс и передают этот список методам Контролера с тем же названием E> — Метод "КассаОбработана", который вызывается из Контроллера обновляет поля таблицы на форме (результат) для конкретной кассы E> — Метод "Подробности": получает от Контроллера последнюю операцию с кассой и открывает форму "Подробный результат"
Зависимость должна идти в одну сторону
Главная форма -> Презентер -> Контроллер
В обратную сторону — только сообщения/события
Поэтому контроллер не должен вызывать методы презентера
Наоборот, презентер должен понять, что операция завершена и сделать обновления формы
Понять может либо дождавшись окончания выполнения метода контроллера, либо получив сообщение от контроллера.
E>Контроллер "Обработка списка касс" E> — Входные данные: список отмеченных касс E> — подписка на событие "Касса обработана" Сценария E> — При срабатывании события получает кассу, ее результат и отправляет Презентеру методу "КассаОбработана" E> — При запросе от Презентера возращает ему последнюю операцию с кассой E>Класс БЛ "Сценарий обработки касс по списку" E> — хранит обработанных список касс E> — хранит для каждой кассы последнюю выполненную операцию E> — Метод "ОбработатьКассы": E> — в цикле для каждой кассы проверяет настройки кассы E> — создает экземпляр "Операции с кассой", вызывает его метод "Выполнить" E> — вызывает подписчик на событие "КассаОбработана" с передачей параметров — Касса, Операция
Этот контроллер не делает ничего полезного, только передает сообщение следующему классу.
Думаю, стоит объединить эти два класса в один класс — АсинхроннаяОбработкаКасс
— получает на вход список касс
— выполняет заданную операцию над этими кассами
— отправляет события, что обработка кассы завершена, предоставляет результаты обработки и лог обработки
E>Класс БЛ "Операция с кассой" (базовый): E> — хранит Результат (в зависимости от операции есть дополнительные реквизиты у результата) E>Класс БЛ "Выгрузка в кассу" — наследник "Операция с кассой"" E> — реализуют конкретную операцию — выгрузка (или загрузка) E> — извлекает данные из БД E> — вызывает методы класса "Обмен в формате ХХХ" E> — сохраняет результат ("Успех" или "Ошибка") E> — устанавливает дополнительные поля результата (количество всех товаров, итоговая сумма)
Лучше результат операции хранить отдельно от самой операции. Т.е. создать класс для хранения результата.
Метод класса должен возвращать результат операции, а у тебя почему-то наследование от "результата операции".
E>Класс "Обмен в формате ХХХ": E> — знает какие файлы надо читать\записывать и в каком формате E> — записывает \ читает даные E> — конвертирует эти данные между форматом Бизнес-логики и форматом ХХХ
E>Как протащить ссылку на Журнал с самого верха до самого низа?
Передавать в конструкторе или методе в каждом классе, который должен писать в журнал.
Либо, как я говорил выше, вообще не передавать IЖурнал, а лог возвращать как список строк внутри "результата операции кассы"
Best regards, Буравчик
Re[8]: Передача лога о выполняемых действиях из подчиненного
Здравствуйте, es3000, Вы писали: E>Вот я и ломаю голову. Не хочется дурь делать.
Если протоколирование работы касс — важная часть проекта, то надо повысить его из диагностических/отладочных средств.
Ввести как компонент бизнес-логики со всеми соответствующими взаимодействиями с DAL.
Может быть, что в результате и различные аналитические отчеты будет проще строить.
Например, если все записи лога хранить в одной таблице РСУБД, то можно будет удобно строить выборки по одной кассе, нескольким, всем...
С несколькими лог-файлами было бы сложнее и реализовывать пришлось бы врукопашную.
Re: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, es3000, Вы писали:
E>Здравствуйте!
E>Подскажите, пожалуйста: E>как правильно делается передача лога (протокола, журнала) о выполняемых действиях в подчиненных модулях на вышестоящий (вызывающий) уровень?
Очень просто передавай свой логгер который будет складывать лог для последующего отображения.
E>Как это делается?
E>Самое простое — это передавать объект ResultArray в качестве параметра во все вызываемые методы.
Используй интерфейс логгера
И в зависимости от потребностей используй разные реализации.
E>Так как например модуль "Обмена в формате ХХХ" уже написан, менять все методы неохота.
Для замены не обязательно менять все методы.
E>А модуль "Работа с файловой системой" вообще не должен знать ни о каких специальных классах вышестоящих модулей.
???
E>Как лучше сделать?
Закажите ПО на стороне
Re[7]: Передача лога о выполняемых действиях из подчиненного уровня
Здравствуйте, qaz77, Вы писали:
Q>Мало ли библиотек, где в callback нет пользовательских параметров.
Ну в общем-то мало, да. Потому что совершенно непонятно, как ими пользоваться, если в каллбеке невозможно понять, к чему этот каллбек относится.
Q>Я к тому, что не стоит загонять себя в угол проектным решением, пытаясь везде передавать контекст явно. Q>Особенно, когда это такая вспомогательно-отладочная штука как лог.
Q>Можно взглянуть на передачу контекста под другим углом. Q>Т.к. контекст передается во все функции, то можно сделать их методами контекста, а соответствующий параметр убрать. Q>Получится такой God-object, в котором сосредоточен весь зависимый от логов функционал. Q>В общем, дурь получается...
Именно поэтому не надо так делать.
Re[4]: Передача лога о выполняемых действиях из подчиненного уровня
Б>Ты точно уверен, что WriteFile должен писать в журнал?
Не совсем так.
Класс "Работа с файловой системой" — это обертка для функций работы с файлами, используемая другими частями приложения для изоляции от конкретной библиотеки и для добавления новой функциональности (например журналирования).
Должно быть так:
class MyFileSystem
{
IJournal mJournal;
function WriteFile (File pFile, Data pAnyData)
{
try
{
mJournal.Info("Начинаем запись в файл.");
openfile(pFile.filename);
writefile{pAnyData};
mJournal.Info("Запись в файл успешна.);
}
catch(...)
{
mJournal.Info("ошибка при записи в файл");
}
}
}
Только в случае обмена с кассой здесь надо сделать журналирование и в системный журнал и в журнал, имеющий отношение к конкретной кассе.