atauenis / fcmd

The File Commander is a modern cross-platform two panel file manager, written in C#.
Other
42 stars 9 forks source link

Added cache for language files #21

Closed Break-Neck closed 10 years ago

Break-Neck commented 10 years ago

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

atauenis commented 10 years ago

Извиняюсь, что малыми частями

Нормально! Если есть желание серьёзно участвовать в проекте, могу дать прямой доступ к репозиторию (сделать collaborator'ом).

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

И что в этом плохого? Языковой файл парсится каждый раз при его загрузке. А грузится он только при вызове LoadLanguage, т.е. только из конструктора. Потом всё уходит в словарь Localization, с которым и работает GetString. Работа с множеством языковых файлов не предусматривается. Если надо, можно перезагрузить языковой файл и повторить всю работу заново (перечитать все необходимые строки через GetString).

Тут изъян в другом, Localizator инициализируется (и соответственно грузит и парсит языковой файл) в каждом классе, т.е. идёт колоссальное повторение кода. Если юзверь возжелает поменять язык на лету, понадобится провести кучу работы, чтобы во всех открытых окнах поменять надписи. Если бы в C# были глобальные переменные, с этим проблем не было бы (повесил событие на доступный везде экземпляр localizator "user language changed" и вертай строки где надо, ан нет, ООП так ООП, никаких "атавизмов" из 80-ых)...

Break-Neck commented 10 years ago

Так я и имел ввиду, что в коде много раз делается new Localization() (17 раз, если точнее). Я сделал так, что он второй раз не грузит язык, а использует уже загруженный словарь. Как по мне, желание изменять файлы языка при работающем приложении довольно странное, но можно сделать отдельную кнопку "Сбросить кэш", хотя уж проще перезапустить приложение.

Глобальные переменные реализуются в C# через статические переменные какого-либо класса, но если они нужны, то, скорее всего, что-то пошло не так.

atauenis commented 10 years ago

Что-то не въезжаю (вечер дня рождения :-) ). Кэш уже есть - Localization - , зачем делать cached_languages? Можно же сделать Localization статическим, добавить статическое свойство "текущий язык", при изменении которого перезагружать словарь, а при GetString, если оно не null / default value (т.е. установлено как минимум однажды) словарь не перезагружать (иначе делать exсeption)...

но если они нужны, то, скорее всего, что-то пошло не так.

А вот про это прошу по подробнее. В visual basic 6 всю жизнь использовал их параллельно с ООП, проблем не возникало, код работает и читается на ура (особенно после чтения readme-dev). Единственный момент, что инициализация программы сложновата по меркам кошерного ООП, т.е. при загрузке программы они все заполняются, если обращаться к чему либо их использующему до их инициализации, первое рушит всю программу намертво... На C#, правда, пишу недавно, могу быть не прав.

Break-Neck commented 10 years ago

С днем рождения! :smiley:

Ну, можно и так, но я умудрился сделать то же самое, оставаясь в рамках ООП: кэш -- простое статическое поле-словарь, в котором хранятся уже загруженные языки. Если язык уже был загружен, то еще раз файл не парсится, а сразу берется результат, фактически, просто прокинуть пару указателей.

Глобальные переменные считаются моветоном из-за кучи потенциальных проблем при модификации программы, один из принципов ООП и есть инкапсуляция -- противоположность идее глобальных переменных. Правда, в ООП можно сделать тоже самое, но объектами (называется God Object), но это тоже анти-паттерн.

Break-Neck commented 10 years ago

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

atauenis commented 10 years ago

Если не делать глобальную переменную типа экземпляр Локализатора, то можно сделать тоже самое, но ООПнее. А именно сделать начинку Localizator статической (в отличии от самого класса). Один раз пропарсить файл (при загрузке программы) и закэшировать его в словаре Localization. При смене языка или его перезагрузке (полезно при отладке) Localization переписать, и обновить UI. Обновление надписей в UI при смене языка сделаю я отдельно, есть идейка, не буду вдаваться в подробности, ждите в ближайших коммитах).

Break-Neck commented 10 years ago

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

Break-Neck commented 10 years ago

Работа с множеством языковых файлов не предусматривается.

Прошу прощения, пропустил эту фразу.

atauenis commented 10 years ago

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

Это полезно при отладке языковых файлов. Я, было дело, занимался переводом нескольких программ с внешними языковыми файлами на русский язык. Бывает, переведёшь файл, посмотришь и ужаснёшься, насколько испорчены оказались склонения и падежи (особенно когда строка в UI формируется из нескольких строк в lng-файле). Проще не перезапускать программу, а быстро исправить ошибку и перезагрузить языковой файл в программе. Так умеет даже Total Commander (умел по крайней мере в v6.5).

atauenis commented 10 years ago

Кэш переделан в одно-языковой.