Календарь на Май 2024 года: calendar2008.ru/2024/may/
Навигация
Главная »  Delphi 

Упростите свои Delphi-приложения - Часть 2


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

1. Введение

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

2. Старый код

Обычно разработчики предпочитают считывать настройки приложения в тот момент, когда пользователь может захотеть их изменить. Когда пользователь закончил редактирование, они снова записываются в реестр. Также, очевидно, что чтение и сохранение настроек происходит при открытии и закрытии формы соответственно. Итак, на главной форме мы имеем какой-то такой код:
Открыть в новом окне РаспечататьСправка
01.procedure TfrmMain.FormShow(Sender: TObject);
02.var
03.  aRegistry: TRegistry;
04.begin
05.  aRegistry := TRegistry.Create;
06.  try
07.    aRegistry.OpenKey('the_registry_path', True);
08.    // FString, FInteger и FBoolean локальные поля
09.    // формы TfrmMain.
10.    FString  := aRegistry.ReadString('string_setting_key');
11.    FInteger := aRegistry.ReadInteger('string_setting_key');
12.    FBoolean := aRegistry.ReadBool('string_setting_key');
13.  finally
14.    aRegistry.Free;
15.  end;
16.end;
17.  
18.procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
19.var
20.  aRegistry: TRegistry;
21.begin
22.  aRegistry := TRegistry.Create;
23.  try
24.    // FString, FInteger и FBoolean локальные поля
25.    // формы TfrmMain.
26.    aRegistry.OpenKey('the_registry_path', True);
27.    aRegistry.WriteString('string_setting_key', FString);
28.    aRegistry.WriteInteger('string_setting_key', FInteger);
29.    aRegistry.WriteBool('string_setting_key', FBoolean);
30.  finally
31.    aRegistry.Free;
32.  end;
33.end;
34.  
35.procedure TfrmMain.mnuEditSettingsClick(Sender: TObject);
36.var
37.  aEditSettingsForm: TfrmEditSettings;
38.begin
39.  aEditSettingsForm := TfrmEditSettings.Create(Self);
40.  try
41.    aEditSettingsForm.TheString := FString;
42.    aEditSettingsForm.TheInteger := FInteger;
43.    aEditSettingsForm.TheBoolean := FBoolean;
44.  
45.    if (aEditSettingsForm.ShowModal = mrOK) then
46.    begin
47.      FString  := aEditSettingsForm.TheString;
48.      FInteger := aEditSettingsForm.TheInteger;
49.      FBoolean := aEditSettingsForm.TheBoolean;
50.    end;
51.  finally
52.    FreeAndNil(aEditSettingsFrom)
53.  end;
54.end;

3. Как это будет работать?

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

4. В чем же проблема?

Выполняется ли код в нужный момент времени?

На мой взгляд события OnShow и OnClose - не лучшее место для выполнения этого кода. А что, если настройки связаны с визуальным отображением формы? Вы действительно хотите загружать и сохранять их при каждом показе формы? А может у Вас есть настройки, которые необходимо загрузить до отображения первой формы? В любом случае Вам может потребоваться загружать или сохранять настройки в разное время работы Вашего приложения. В данном примере Вы загружали их только при загрузке формы. Плохое решение - просто переписать или скопировать этот же код в другие участки проекта. Верите или нет, но это случается довольно часто.

Что произойдет в случае ошибки при загрузке/сохранении настроек?

Данный код не идеален, и интересные вещи могут произойти, если в реестре отсутствует требуемый ключ. Код вызовет исключение, что приведет к загрузке/сохранению только части настроек и получению неверных значений. В нашем случае было бы неплохо использовать значение по умолчанию при отсутствии соответствующего ключа в реестре. Кроме того, когда пользователь открывает форму редактирования настроек и закрывает ее нажатием кнопки OK, новые настройки передаются главной форме, но еще не сохраняются в реестре. Если теперь Вы решите взять настройки из реестра в другом участке кода, то получите несоответствие текущим настройкам на главной форме.

Неужели главная форма должна загружать/хранить настройки?

Нет, абсолютно нет! Что если мы захотим создать консольную версию приложения? Нам все еще может понадобиться загружать/сохранять настройки из реестра, но никаких форм у нас не будет. А что если мне нужно создать поток для вычислений, и считывать настройки непосредственно в этом потоке? Как видите, главная форма на самом деле не должна отвечать за загрузку/хранение настроек. Она может вызывать какой-либо метод для этого, но основной код никогда не должен находится в коде главной формы. Еще одно мое правило заключается в том, что форма должна содержать только код, влияющий на визуальные характеристики ее самой или ее компонентов. Загрузка/сохранение настроек никак не относится к визуальному отображению формы, соответственно код ей принадлежать не должен. Вам может понадобиться изменить некоторые визуальные характеристики на основании загруженных настроек, но само чтение - не в компетенции формы.

5. Есть ли лучшая альтернатива?

Сказать, что это плохо - не трудно, но в таком случае нужно предложить что-то получше. Давайте немного подумаем, что мы хотим, и что нам требуется. В общем, нам нужен кто-то, кто будет загружать и сохранять настройки приложения. Было бы замечательно, если бы у нас был код, который можно было использовать в любом приложении в будущем. На самом деле не важно, какое количество настроек мы хотим сохранить, как они называются, или в каком формате они хранятся, единственное, что нам нужно - возможность Загрузки/Сохранения/Редактирования и Применения их. Как это будет сделано не важно, но, предположим, класс ApplicationSettings позволяет это делать. Если мы хотим применить настройки к приложению, нужно добавить код наподобие следующего:
Открыть в новом окне РаспечататьСправка
01.var
02.  aApplicationSettings: TApplicationSettings;
03.begin
04.  aApplicationSettings := TApplicationSettings.Create('');  
05.  try
06.    // Код для загрузки настроек  
07.    aApplicationSettings.LoadFromRegistry;
08.      
09.    // Код для редактирования настроек
10.    if (aApplicationSettings.EditSettings) then    
11.    begin
12.      // Настройки изменены, и, возможно, 
13.      // мы что-то хотим при этои сделать.
14.    end;
15.          
16.    // Код для сохранения настроек
17.    aApplicationSettings.SaveToRegistry;    
18.  finally
19.    FreeAndNil(aApplicationSettings);  
20.  end;
21.end;

Кто что делает?

Как видите, наша приложение/форма или что бы то ни было не должны знать о том, как считывать настройки, сохранять, отображать или редактировать их. Единственное, нужно знать, что это умеет класс TApplicationSettings. С другой стороны наш класс настроек должен знать какие настройки нужны приложению, какие это настройки, и как их необходимо загружать/сохранять.

Есть ли преимущества у данного подхода?

Конечно, иначе бы я не стал тратить на это время. Наша главная цель - использовать Delphi как объектно-ориентированный язык программирования, а не просто как RAD-инструмент. В дальнейшем мы создадим несколько классов, основанных на данном подходе и основном смысл в том, что использовать эти классы когда нам необходимо. Если завтра нам потребуется написать другое приложение и ему будет необходимо загружать/сохранять настройки, мы только укажем классу, какие это настройки, их название и тип. Остальная часть кода останется такой же. Мы потратим больше времени на создание класса настроек и написание соответствующего кода, но в следующий раз, все (почти все) уже будет готово.

Что дальше?

Мы уже многое обдумали и обговорили, но толком ничего не запрограммировали. Скорее всего немногие думают, что способны написать код уже после прочтения этих двух статей. Конечно, это возможно, я видел такое... Печально, но однажды я был тем, кого наняли для отладки приложения 5-ти летней давности в поисках ошибки в работе некоторых классов. Я также был в ситуации, когда пришлось пробегаться по тысячам строчек кода, удивляясь, почему некоторые настройки никогда не сохраняются или получают неверные значения. И конечно, я всегда желал, что они уделили подумали над кодом до его написания :-P. В любом случае, в следующий раз я покажу Вам, как это сделать, и надеюсь, поделюсь кодом.



 

 Компоненты Indy, применяемые в Delphi 6 (документация).
 Математика и Delphi (исходники).
 Borland Delphi 2006.
 Автозагрузка в Delphi (исходники).
 Советы по программированию на DELPHI (ч.1).


Главная »  Delphi 

© 2024 Team.Furia.Ru.
Частичное копирование материалов разрешено.