Строки в отдельном файле .pas

Возможно, это не то место для этого вопроса, если вы не можете его переместить. Я пометил как Delphi/Pascal, потому что это то, над чем я работаю в банкомате, но я думаю, это может относиться ко всему программированию.

Во всяком случае, я делаю некоторую очистку кода и думаю о перемещении всех строк в моей программе в отдельный файл .pas. Есть ли плюсы и минусы в этом? Стоит ли это делать?

Чтобы уточнить: я имею в виду, что я буду создавать отдельный файл, Strings.pas, в нем я буду делать все свои текстовые строковые переменные.

Ex

Текущий код

 Messages.Add('The voucher was NOT sent to ' + sName+
                          ' because the application is in TEST MODE.');
 Messages.Add('Voucher Saved to ' + sFullPath);
 Messages.Add('----------------------------------------------------------');

Новый код будет выглядеть примерно так:

Messages.Add(sMsgText1 + '' + sName + '' + sMsgText2 + '' + sFullPath)

Файл Strings.pas будет содержать все строковые данные. Надеюсь, это имеет смысл


person James West    schedule 15.07.2011    source источник
comment
Зачем вам это делать? Конечно, вы можете поместить строки в какой-нибудь другой файл .pas, затем проанализировать файл .pas в своем файле, который содержит код, и использовать эти строки, хотя в этом случае я дам файл строк расширение .txt.   -  person    schedule 15.07.2011
comment
Вы можете сделать это, загрузив файл в строку, а затем проанализировав строку. Я не знаю паскаля, поэтому не могу привести вам пример.   -  person    schedule 15.07.2011
comment
@Aleksandar OP думает о написании файла .pas, содержащего длинный список объявлений const.   -  person David Heffernan    schedule 15.07.2011
comment
Я не знаю насчет паскаля. Но в c вы можете объявить заголовочный файл, содержащий только константы (определения, typedefs и const vars)   -  person    schedule 15.07.2011
comment
@Aleksandar, если ты не знаешь Delphi или Pascal, то почему ты пытаешься ответить на вопрос (даже в комментариях)? :)   -  person Ken White    schedule 16.07.2011
comment
@Ken: Я думаю, что это довольно универсальная проблема, решение которой в C, C# и т. д. такое же, как и в Pascal. Но на самом деле это немного удивляет.   -  person Rudy Velthuis    schedule 16.07.2011
comment
В .Net стандартным способом являются файлы строк ресурсов (также для поддержки мультикультурных приложений).   -  person mjn    schedule 18.07.2011


Ответы (6)


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

Но код типа:

Messages.Add(sMsgText1 + '' + sName + '' + sMsgText2 + '' + sFullPath)

не лучше, чем такой код:

Messages.Add('The voucher was NOT sent to ' + sName+
                      ' because the application is in TEST MODE.');

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

Во-вторых, причина перемещения строк, чтобы сохранить связанные элементы вместе и упростить их изменение. Что, если вы хотите изменить приведенное выше сообщение, чтобы вместо «Файл 'foo' в пути 'bar'...» оно звучало как «Файл bar\foo is...»? Вы не можете: способ построения сообщений по-прежнему фиксирован и разбросан по всему коду. Если вы хотите изменить несколько сообщений, чтобы они были отформатированы одинаково, вам нужно будет изменить множество отдельных мест.

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

Рефакторинг на шаг впереди

Вместо этого я бы предложил более агрессивный рефакторинг вашего кода сообщения. Вы определенно на правильном пути, когда предлагаете перенести сообщения в отдельный файл. Но не просто перемещайте строки: перемещайте и функции. Вместо большого количества Messages.Add('...'), разбросанных по коду, найдите общее подмножество создаваемых вами сообщений. Многие будут очень похожи. Создайте семейство функций, которые вы можете вызывать, чтобы все похожие сообщения были реализованы с помощью одной функции, и если вам нужно изменить их формулировку, вы можете сделать это в одном месте.

Например, вместо:

Messages.Add('The file ' + sFile + ' in ' + sPath + ' was not found.');
... and elsewhere:
Messages.Add('The file ' + sFileName + ' in ' + sURL + ' was not found.');

имеют одну функцию:

Messages.ItemNotFound(sFile, sPath);
...
Messages.ItemNotFound(sFileName, sURL);

Ты получаешь:

  • Централизованные строки сообщений
  • Централизованные функции сообщений
  • Меньше дублирования кода
  • Более чистый код (без сборки строк в вызове функции, только параметры)
  • Легче перевести — предоставьте альтернативную реализацию функций (не забывайте, что простого перевода подстрок может быть недостаточно, вам часто нужно иметь возможность существенно изменить формулировку.)
  • Четкое описание сообщения в имени функции, например ItemNotFount(item, path), что приводит к
  • Более понятный код, когда вы его читаете

Звучит неплохо :)

person David    schedule 18.07.2011
comment
Пока этот процесс шел, пока я думал о переменах ради перемен, я также четко вижу плюсы и минусы. @ Дэвид М, я принимаю твой ответ как ответ, потому что ты направил меня в очень хорошем направлении. - person James West; 18.07.2011
comment
@JamesW - я обнаружил, что использование formatStrings очень полезно для такого типа работы. Определите строковую константу, например: 'const eMsg='файл %s не найден'. Затем вызовите свою центральную функцию, отформатировав константу: Messages.ItemNotFound(format(eMsg,['missing_file'])) - person Vector; 20.07.2011

Я думаю, что имеет смысл перенести все строковые константы в один модуль. Это значительно упрощает изменение текстов, особенно если вы хотите перевести их на другие (человеческие) языки.

Но вместо строк, почему бы вам не сделать то, что я обычно делаю, то есть использовать resourcestring. Таким образом, ваши строки могут быть изменены кем-то другим с помощью редактора ресурсов без перекомпиляции.

unit Strings;

resourcestring
  strMsgText1 = 'The voucher was NOT sent to ';

etc...

Но такую ​​строку, вероятно, лучше сделать так:

resourcestring
  strVoucherNotSent = 
    'The voucher was NOT sent to %s because the application is in TEST MODE.';
  strVoucherForNHasValueOf =
    'The voucher for %s has a value of $%.2f'; 

Преимущество этого в том, что в некоторых языках расположение и порядок таких замен отличается. Таким образом, переводчик может размещать аргументы там, где это необходимо. Конечно, приложение должно затем использовать Format() для обработки строки:

Messages.Add(Format(strVoucherNotSent, [sName]));
Messages.Add(Format(strVoucherSavedTo, [sFullPath]));
Messages.Add(Format(strVoucherForNHasValueOf, [sName, dblValue]));
person Rudy Velthuis    schedule 15.07.2011
comment
Вы не упоминаете о недостатках перемещения всех строк, констант и т. д. в отдельные файлы. Затем они удаляются из кода, который на них ссылается, что может затруднить обслуживание. Хорошим примером является последняя строка кода в вашем ответе. Я думаю, что это одна из тех проблем, где у вас есть конкурирующие интересы, которые тянут в противоположных направлениях. Каждый подход имеет как плюсы, так и минусы. - person David Heffernan; 16.07.2011
comment
Я думаю, что это упрощает обслуживание или, по крайней мере, не усложняет его вообще. Вместо буквальных строк ему следует использовать осмысленные имена констант. Поддерживать тексты намного проще. Это ИМО то, что должен делать каждый, кто пишет нетривиальную программу. - person Rudy Velthuis; 16.07.2011
comment
В чем проблематична последняя строка кода в моем ответе? Имя константы совершенно ясно дает понять, что должен передавать текст, хотя и не дает точного текста. Для переводов, где значение, возможно, должно быть помещено перед именем, это единственное полезное решение. В этом случае строка формата должна, конечно, использовать форматирование, чтобы указать, какой аргумент и где используется. - person Rudy Velthuis; 16.07.2011
comment
Как только логика вывода становится сложной, становится очень запутанным, если ваш текст спрятан в другом месте. - person David Heffernan; 16.07.2011
comment
@David: я совершенно не согласен. Я не думаю, что это сбивает с толку. Понятно, где ВСЕ тексты: в этом едином блоке. В отдельном блоке они могут быть сгруппированы по назначению или блоку и разделены пустой строкой и комментарием. И это также упрощает соблюдение орфографии, грамматики и т. д. ИМО, это хорошая практика программирования. Но давайте согласимся, что мы не согласны. Люди должны делать то, что они хотят. Я просто хотел показать, как это можно сделать, и что есть люди, такие как я, которые думают, что это имеет большой смысл. Вы заметили, что RTL и VCL делают то же самое? - person Rudy Velthuis; 16.07.2011
comment
@David: вы упомянули сложную логику вывода. Что ты имел в виду? - person Rudy Velthuis; 16.07.2011
comment
Петли, решения, множественность, раскладка. Я часто ловлю себя на том, что собираю кусочки текста. - person David Heffernan; 16.07.2011
comment
VCL такой, какой он есть, потому что он переведен. VCL также имеет на много порядков меньше текста и менее сложную логику вывода, чем приложение, с которым я работаю. - person David Heffernan; 16.07.2011

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

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

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

person David Heffernan    schedule 15.07.2011
comment
Лучший пример, который я могу сейчас придумать, — этоglade.GUI Builder для GTK, экспортирующего файлы .xml. - person ; 15.07.2011
comment
Я думал в том же направлении. Основная мотивация заключается в том, что некоторые приложения используют очень похожий или даже один и тот же текст несколько раз. Я знаю, что мог бы просто объявить их как глобальные константы, но именно тогда я подумал, собираюсь ли я сделать некоторые из них глобальными константами, почему бы просто не сделать их все и припарковать их в другом файле. - person James West; 15.07.2011
comment
@JamesW Обязательно объявите дубликаты общими константами. Но вам не нужно менять таким образом все ваше приложение. - person David Heffernan; 15.07.2011
comment
Чем больше я думал об этом, тем больше я видел, что это могло быть изменением ради изменения. Я вижу в этом небольшие преимущества (главным из них является быстрый поиск и редактирование строк). Однако недостатки, похоже, перевешивают, время на реализацию, удобочитаемость для других, которым может потребоваться изменить мой код и т. д. - person James West; 15.07.2011
comment
Я думаю, что для любой нетривиальной программы всегда полезно иметь свои константы (особенно строки) в отдельном файле. Иногда их приходится менять, и тогда их гораздо проще найти в одном-единственном файле, чем во всех исходных файлах приложения. Не только для переводов, но и когда я проверяю все свои строки на согласованное использование слов, запятых и т. д. Это довольно просто сделать с текущими возможностями рефакторинга в Delphi IDE. - person Rudy Velthuis; 16.07.2011
comment
@James: если вы выбираете читаемые имена для констант (я имею в виду что-то более значимое, чем sMsgText1), имеет смысл разделить строки, IMO. Вы знаете преимущества. Я не вижу никаких недостатков, кроме того, что это занимает некоторое время. Но IDE может помочь вам реорганизовать такие строки. Другой ответ Semy тоже: это делает изменение, проверку орфографии и грамматики, проверку на согласованность и т. Д. НАМНОГО проще. - person Rudy Velthuis; 16.07.2011
comment
@Rudy, если вы выберете читаемые имена для констант. Это легко сказать, но не всегда так просто сделать. - person David Heffernan; 16.07.2011
comment
Я думаю, это очень легко. Вы можете копировать текст почти дословно, как это делает среда IDE при рефакторинге таких строк, или указать намерение, для чего он используется. Я всегда делаю это для программы или эксперта с несколькими единицами. Я не думаю, что мои исходные файлы становятся нечитаемыми из-за этого. Наоборот: мои постоянные имена отражают намерение, цель строки, а не буквальный текст. Я думаю, что это делает исходный код очень читабельным, особенно если текст довольно длинный. Длинные тексты могут отвлекать от фактического кода. - person Rudy Velthuis; 16.07.2011
comment
Я всегда с Руди, за исключением всего, что Руди объяснил. Я нахожу исходный файл Delphi, замусоренный множеством длинных жестко закодированных строк, уродливым и трудным для чтения. strings Мне интересно, не нужно ли Дэвиду использовать опцию «перейти к объявлению», доступную в его версии Delphi... - person Vector; 16.07.2011
comment
@Mikey @Rudy Помните, что у OP есть существующая кодовая база и нет планов по переводу. Стоит ли менять преимущества? Будет ли время, потраченное на изменение, самым прибыльным? - person David Heffernan; 16.07.2011
comment
Даже если планов на перевод нет, все равно иногда необходимо менять константы и строковые литералы, например. исправить правописание или заставить их все последовательно использовать одни и те же термины и т. д. Иметь их в одном месте — IMO лучший способ добиться этого. Таким образом, прямой выгоды может и не быть, но весьма вероятно, что долгосрочная выгода будет, если это нетривиальная программа. В частности, код, на который вы не смотрели более 6 месяцев, трудно снова просмотреть, и наличие ваших материалов в определенных местах делает такие вещи намного проще, IMO. - person Rudy Velthuis; 16.07.2011
comment
@david - Стоит ли менять преимущества? - абсолютно, по причинам объясненным. Обычно это просто сделать, и оно того стоит. Код, полный жестко закодированных строковых сообщений, кричит «на любителя». - person Vector; 17.07.2011
comment
@mikey тогда я просто любитель - person David Heffernan; 17.07.2011
comment
@ Дэвид - твоя репутация идет впереди тебя - очевидно, ты не любитель. Просто, возможно, в каком-то вашем коде есть «любительские аспекты»… LOL. Итак, время для рефакторинга... (опять же, когда не "время для рефакторинга"... но мы также должны проделать некоторую работу....) - person Vector; 18.07.2011

Если вы хотите перевести свое приложение, рассмотрите возможность использования Gnu GetText для delphi, также известного как dxGetText. Это лучше, чем помещать ваши строки в отдельный файл .pas, потому что это позволяет вам включить перевод без каких-либо специальных инструментов, какой-либо перекомпиляции, даже конечными пользователями.

person Warren P    schedule 15.07.2011
comment
Это действительно хорошая альтернатива. Несколько таких файлов я уже перевел на голландский или немецкий язык для чьих-то программ. Я никогда не видел исходный код, только исходный текстовый файл на английском языке, и я отправил обратно переведенный файл. - person Rudy Velthuis; 16.07.2011

Что ж, консенсус здесь, кажется, склоняется в пользу стороны, и я полностью с этим согласен. Неправильное чрезмерное использование строковых литералов может привести к тому, что ваш источник получит строковую типизацию.

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

Но довольно существенным недостатком является необходимое время для создания этого отдельного исходного файла. Вы можете применить этот хороший метод программирования в следующем проекте. Это полностью зависит от того, есть ли у вас достаточно времени (например, хобби-проект) или крайний срок, есть ли у вас следующий проект или нет (например, студент), или вы просто хотите немного попрактиковаться. Как и ответы и комментарии David H, как и все решения, которые вы сделать, вы должны взвесить преимущества.

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

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

Если у вас есть роскошь или необходимость: сделайте это. Но я бы взял это на следующий проект.

person NGLN    schedule 18.07.2011
comment
Я не понимаю, какое отношение группировка строковых литералов имеет к строковой типизации. - person Marco van de Voort; 25.07.2011
comment
@Marco Ну, в одном примере говорится Передача сообщений без использования типизированных сообщений. Но поскольку термин stringly typed является вымышленным, я, возможно, неправильно понял его определение. - person NGLN; 25.07.2011

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

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

(*) использование dxgettext в «общих» каталогах.

person Marco van de Voort    schedule 25.07.2011