Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.05.02;
Скачать: CL | DM;

Вниз

Про глобальные переменные   Найти похожие ветки 

 
Style ©   (2004-04-08 23:26) [40]


> а там уже храни что угодно.


Главное это что угодно использовать когда нужно. Иначе такая путанитца может получиться.


 
nikkie ©   (2004-04-08 23:27) [41]

>Представь, как это удобно.
представляю. берем TEnvironment, принимаем гениальное решение сделать его максимально гибким, разрешить хранить в нем не только стандартные типы, но и любые записи и классы, и, воспользовавшись идеей panov-а, делаем метод доступа
TEnvironment.GetValue(ValueName: String): Variant;
получаем пример того, как хорошую идею можно превратить в кошмар на улице вязов. прошу прощения за некоторое утрирование.


 
Gero ©   (2004-04-08 23:31) [42]


> [41] nikkie ©   (08.04.04 23:27)

Да нет, варианты здесь ни к чему.
>Можно перегрузку сделать(overload) - это больше подойдет.
Да думаю лучше у vuk"a спросить, как он это реализовывает.


 
nikkie ©   (2004-04-08 23:42) [43]

>Можно перегрузку сделать(overload) - это больше подойдет.
нельзя сделать перегрузку, изменив только тип возвращаемого значения.

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


 
Игорь Шевченко ©   (2004-04-09 00:14) [44]


> но ты считаешь что так делать надо, потому что круто


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

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

Мне, кстати, в свое время очень помогла взглянуть свежим взглядом на некоторые вещи книжка Мартина Фаулера: "Рефакторинг или улучшение существующего кода". Если выбросить из нее весь XP-шный стиль, и вдумчиво переработать рекомендации, очень неплохой источник информации, почему та или иная конструкция имеет право на существование, и в чем ее плюсы/минусы/отличия от других конструкций.


 
Gero ©   (2004-04-09 00:25) [45]


> [43] nikkie ©   (08.04.04 23:42)
> но ты считаешь что так делать надо, потому что круто

Ошибаешься. Я никогда не делаю что-либо "потому что круто".
Хм, скажи, чем будет плохо если все глобальные переменные запихнуть в один класс?

>то наследники твоего кода проклянут тебя
Объясни, может я чего-то не понимаю?


 
nikkie ©   (2004-04-09 00:55) [46]

блин... я дико прошу прощения. потерялось слово "если"
... но если ты считаешь ...

>Хм, скажи, чем будет плохо если все глобальные переменные запихнуть в один класс?
плохого я не вижу. впрочем и особых преимуществ тоже. только осознание того, что "все правильно сделал" (с) реклама. это если сделать
gSettings.VarName вместо gVarName.

а вот если сделать так: gSettings.GetValue("VarName"), то минусы имхо очевидны. разумеется, я говорю о конечном наборе заранее определенных разнотипных переменных, а не массива однотипных.

>>то наследники твоего кода проклянут тебя
>Объясни, может я чего-то не понимаю?

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

>Игорь Шевченко
>Всякий овощ приносит пользу, будучи употребленным в нужное время в нужном месте.

за сие и ратую :))

во избежание молотьбы воды в ступе - может вы с vuk-ом приведете пример, как именно устроены ваши классы для хранения настроек?


 
Gero ©   (2004-04-09 01:08) [47]


> nikkie ©   (09.04.04 00:55)

> блин... я дико прошу прощения. потерялось слово "если"
> ... но если ты считаешь ...

Ааа, сразу бы так, а то я думаю: что за наезды :))


> попробуй работать с глобальными переменными так, как предложил
> [31] panov - после этого тебе не захочется проклясть автора
> этой технологии?

Да уж.

> nikkie
#ifdef личная переписка & offtop
Ты почту не проверяешь, тебе некогда или просто в облом мне писать?
#endif


 
nikkie ©   (2004-04-09 01:12) [48]

>Gero
не разобрался с проблемой пока.


 
Piter ©   (2004-04-09 01:12) [49]

Игорь Шевченко (08.04.04 21:44) [27]
А я использую класс TSettings


Ни фига себе... вообще-то это я использую класс TSettings... ой, точнее запись


 
Vuk ©   (2004-04-09 01:53) [50]

to nikkie:
>в синглтоны, надеюсь? :)
Сам по себе Envirobment может быть синглетоном или не быть им (если используются исключительно методы класса).

>а то где же хранить данные, к которым обращаются классовые
>методы - не в глобальных же переменных :))
Если это классовые методы, то данные, понятное дело, хранятся в переменных. Но глобальными они не будут (будет видимость в пределах раздела реализации модуля) и возможности изменить их кроме как через методы TEnvironment не будет.

>делаем метод доступа
>TEnvironment.GetValue(ValueName: String): Variant;
А вот так я делать пожалуй буду только в том случае, если класс TEnvironment должен будет предоставлять сервис на манер ini-файлов. В остальном же все обычно делается несколько иначе. Если нужно получать какое-то значение (простого или составного типа - неважно) то заводятся соответствеющие методы, которые будут работать с этими данными и только с ними а результат работы будет строго типизирован. Для большей же гибкости могут создаваться дополнительные классы управления конфигурацией (к примеру DatabaseConfigurationManager, UserConfigurationManager и т.п.) и TEnvironment содержит методы, которые возвращают ссылки на экземпляры этих классов. Это позволяет не загромождать TEnvironment множеством методов доступа к конкретным данным.


 
Думкин ©   (2004-04-09 07:16) [51]

TButton ©   (08.04.04 19:40) [20]
>Но чей код эффективней?
чей?

Ну примерно так - программист в США в среднем пишет около 7700 строк кода в год, а в других странах - 16700 строк. Но если использовать понятие "функциональная точка", то производительность у первых 63,1 фт, а у вторых менее 30. Это из той же книги, не мое. Но я думаю смысл ясен и объяснение можно найти. Вы о СММ или CBP слышали?

> Игорь Шевченко ©   (08.04.04 21:44) [27]
> panov ©   (08.04.04 21:28)
> А я использую класс TSettings "для определения глобальных
> настроек,

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


 
Polevi ©   (2004-04-09 08:16) [52]

>Anatoly Podgoretsky ©   (08.04.04 22:23) [32]
TSettings=class(TPersistent) удобен тем что его можно сериализовать
для добавления нового парметра настроек достаточно добавить published св-во


 
TUser ©   (2004-04-09 08:20) [53]

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


 
int64   (2004-04-09 10:26) [54]

TButton ©  
Позвольте несколько ваших слов:

> в одной проге была глобальная переменная users: array...
> да, и был отдельный юнит с функциями для работы с этим массивом
> (преимущественно - поиск и выдирание сведений о конкретном
> юзере)
...
> а если нужен обмен данными между модулями? каждый раз передавать
> ссылку на данные?
...
> модули они же ведь и нужны чтоб упростить написание программы


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

Мой совет: избавляйтесь от рудиментов модульно-функционального программирования.


 
DiamondShark ©   (2004-04-09 11:10) [55]

А у меня в каждой программе куча глобальных переменных: Application, Screen, Mouse...


 
Странник ©   (2004-04-09 11:31) [56]

> int64 [54]

> Мой совет: избавляйтесь от рудиментов модульно-функционального
> программирования

а зачем?
мне вот больше импонирует точка зрения  Юрий Зотов ©   (08.04.04 20:48) [23]


 
int64   (2004-04-09 12:06) [57]

Не думаю , что Юрий Зотов в своём ИМХО подразумевал глобальную переменную со списком функций над ней в отдельном модуле. Когда может понадобиться наследование и виртуальные методы над этим модулем.
Я тоже не отрицаю процедурное программирование. Но всему свое место.


 
Anatoly Podgoretsky ©   (2004-04-09 12:28) [58]

ЮЗ подразумевал одно - подумать и применить нужное


 
Vuk ©   (2004-04-09 12:30) [59]

to int64   (09.04.04 10:26) [54]:
>Мой совет: избавляйтесь от рудиментов модульно-функционального
>программирования.
Чего-чего? Модульно-функционального? Во-первых модульность не трожьте, а во-вторых вы функциональное программирование с процедурным не путаете?


 
int64   (2004-04-09 12:33) [60]

Vuk ©   (09.04.04 12:30) [59]
Ну понятно, что оговорился.


 
Vuk ©   (2004-04-09 12:36) [61]

to int64   (09.04.04 12:33) [60]:
>Ну понятно, что оговорился.
Понятно. :o) Но модульность все равно не трожьте, она есть рулез. :o)


 
Матлабист   (2004-04-09 15:31) [62]

Про многопоточность никто не вспоминал?


 
Wizard_Ex ©   (2004-04-09 16:45) [63]

По поводу класса TSettings

Написать такой класс как TSettings по своему вкусу не составляет особого труда, зато польза от этого мне кажется немаленькой,
Я не против использования глобальных переменных - если оно необходимо, почему бы и нет, но в достаточно большом проекте ИМХО лучше использовать спец. класс.
Игорь Шевченко © - я ЗА.

И также по поводу:

> panov ©   (08.04.04 22:11) [31]
> Мне кажется, очень удобно будет обращаться так:
>
> PathData := MySettings.Value("MainSection","PathData");
> MySettings.Value("MainSection","PathData") := PathData;
> -)


Можно еще просто не использовать секции и хранить все вместе, может не удобно - инифайл будет свалкой, но обращаться можно еще и так - визуально смотриться проще и не надо мучаться вспоминать что и где, в какой секции, лежит:

 PathData:=MySettings["PathData"];
 MySettings["PathData"]:=PathData;

Для этого класс должен иметь свойство типа
property Settings[const Name: String]: Variant read GetSettings write SetSettings; default;
Variant наверно подойдет для всех нужд по хранению настроек.
Все остальное скрывается внутри класса и никто не морочит себе голову лишней возней с сохранением и т.д. и т.п.


 
Wizard_Ex ©   (2004-04-09 18:37) [64]

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


 
TButton ©   (2004-04-09 19:36) [65]

re 54, 57
Просто я обрисовал ситуацию в двух словах. Побоялся, что запинают. А если подробнее то дело обстояло так. users: array of TStringList; это во-первых, в MainUnit список юзеров загружался, обрабатывались события сокетов, сообщения от юзеров, результат этой обработки - изменение содержимого аккаунтов, а юнит с утилитами просто упрощал обработку, т.е. я мог просто не заморачиваясь вызвать функцию UserName(VNUM) и т.д. и т.д.
а насчет классов, знаете, мне кажется я до них еще не дорос. у меня только начинает складываться общее представление о них. сам по старинке пользуюсь object"ами, к коим с таким трудом приучился в Паскале.


 
YurikGl ©   (2004-04-09 19:51) [66]

>>Ну примерно так - программист в США в среднем пишет около 7700 строк кода в год, а в других странах - 16700 строк.

Видимо, программисты в других странах пишут на ASM

:)


 
Knight ©   (2004-04-09 20:17) [67]

По своему скромному опыту скажу... Есть опраданные случаи использования глобальных переменных, но их круг, в основном, ограничен глобальными же настройками, которые используются сразу в нескольких модулях и при этом зачастую вообще не меняют своих значений при работе программы. Но в любом случае они должны иметь специальные имена, чтобы было легче отследить места их использования, например, иметь какую-то приставку (G_DBPath) или группироваться в отдельный тип (типа, TSettings=record, class, object - кому, что ближе)

Но самой опасной остаётся глобальная переменная User:TUser;
за этой нужен глаз да глаз, а то можно таких глюков наловить, что мало не покажется :)


 
Anatoly Podgoretsky ©   (2004-04-09 20:21) [68]

С этим просто TRestrictedUser = class(TUser)


 
Anatoly Podgoretsky ©   (2004-04-09 20:23) [69]

TUser должен быть базовым классом с абстрактными методами.


 
Vuk ©   (2004-04-09 20:28) [70]

Мой коллега, который в нашей софтине делал подсистему печати отчетов на основе FastReport постоянно материт этот генератор отчетов за стиль в котором он написан. Главные проблемы создают глобальные переменные.


 
Knight ©   (2004-04-09 20:39) [71]

[68] Anatoly Podgoretsky ©   (09.04.04 20:21)
Как не назови, а доверять этому классу (даже ограниченному) низя ни при каких обстоятельствах... рубить, надо, на корнь любую самодеятельность, шаг вправо, шаг влево - стрелять без предубеждений :)


 
Anatoly Podgoretsky ©   (2004-04-09 21:13) [72]

Vuk ©   (09.04.04 20:28) [70]
Не единственная, не знаю как в новых версиях, но было еще более неприятный момент

try
  обработка
except
end


 
vuk ©   (2004-04-09 21:24) [73]

to Anatoly Podgoretsky ©   (09.04.04 21:13) [72]:
Ну обычно там еще хлеще, то есть вообще без всякой обработки исключений. Типа того:

st := TMemoryStream.Create;
//что-то сделали с потоком
st.Free;


 
Knight ©   (2004-04-09 21:28) [74]


> [72] Anatoly Podgoretsky ©   (09.04.04 21:13)
> try
>   обработка
> except
> end


Действительно неприятная весчь... поубывав бы


 
panov ©   (2004-04-09 21:47) [75]

Ну вот... к вопросу о хранении глобальных параметров-)
Наклепал немного кода.


{
 Класс для хранения настроек программы в ini-файле.
}
unit uApSettings;

interface

uses
 windows,Sysutils;

type
 TRecParam = record
   rSec,
   rNameValue: PChar;
   rParamData: Variant;
 end;

 TSettings = class(TObject)
   private
     FIniName: String;
     FParams: array of TRecParam;
     FSectionName: String;
     procedure FSetIniName(aIniName: String);
     procedure RecInit(var aRec: TRecParam;aSec,aNameValue: String;aValue: Variant);
     procedure RecFree(var aRec: TRecParam);
     procedure AddRecToFParams(aNameValue: String; aValue: Variant);
     procedure ClearFParams;
     procedure LoadParams;
     function FGetParam(aNameValue: String):Variant;
     procedure FSetParam(aNameValue: String;aValue: Variant);
   protected
   public
     constructor Create(aIniName:String="");
     destructor Destroy;override;
     property IniName: String read FIniName write FSetIniName;
     property Params[aNameValue: String]: Variant read FGetParam write FSetParam;
   end;

var
  AppSettings: TSettings;

implementation

constructor TSettings.Create(aIniName:String="");
var
 Len: Integer;
begin
 if Assigned(AppSettings) then
   raise Exception.Create("Create TSettings: Error, object already exists");
 if FIniName = "" then
 begin
   FIniName := ParamStr(0);
   Len := Length(FIniName);
   FIniName[Len]   := "i";
   FIniName[Len-1] := "n";
   FIniName[Len-2] := "i";
 end
 else FIniName := aIniName;
 FSectionName := "AppParameters";
 LoadParams;
end;

destructor TSettings.Destroy;
begin
 ClearFParams;
 AppSettings := nil;
 inherited;
end;

procedure TSettings.FSetIniName(aIniName: String);
begin
 ClearFParams;
 FIniName := aIniName;
 LoadParams;
end;

procedure TSettings.RecInit(var aRec: TRecParam;aSec,aNameValue: String; aValue: Variant);
var
 Len: Cardinal;
begin
 Len := Length(aSec);

 try
   ReallocMem(aRec.rSec, Len+1);
   aRec.rSec[Len] := #0;
   Move(aSec[1],aRec.rSec^,Len);

   Len := Length(aNameValue);
   ReallocMem(aRec.rNameValue, Len+1);
   aRec.rNameValue[Len] := #0;
   Move(aNameValue[1],aRec.rNameValue^,Len);

   aRec.rParamData := aValue;
 except
   raise Exception.Create("TSettings: RecInit. Unknown error :-(");
 end;

end;

procedure TSettings.RecFree(var aRec: TRecParam);
begin
 try
   if aRec.rSec<>nil then
   begin
     FreeMem(aRec.rSec);
     aRec.rSec := nil;
   end;
   if aRec.rNameValue<>nil then
   begin
     FreeMem(aRec.rNameValue);
     aRec.rNameValue := nil;
   end;
 except
   raise Exception.Create("TSettings: RecFree. Unknown error :-(");
 end;

end;

procedure TSettings.AddRecToFParams(aNameValue: String; aValue: Variant);
var
 Len: Cardinal;
begin
 Len := Length(FParams);
 SetLength(FParams,Len+1);
 RecInit(FParams[Len],FSectionName,aNameValue,aValue);
end;

procedure TSettings.ClearFParams;
var
 i: Integer;
begin
 for i := 0 to Length(FParams)-1 do RecFree(FParams[i]);
 SetLength(FParams,0);
end;

procedure TSettings.LoadParams;
var
 i: Integer;
 buf: array of Char;
 Len,LenRes: Integer;
 Names,Params: array of String;
 s: String;
 p: PChar;
begin
 Len := 8192;
 LenRes := 0;

 SetLength(buf,Len);

 repeat
   if LenRes=Len-2 then
   begin
     Len := Len*2;
     SetLength(buf,Len);
   end;
   LenRes := GetPrivateProfileSection(PChar(FSectionName),@buf[0],Len,PChar(FIniName));
 until LenRes<>Len-2;

 if LenRes=0 then
 begin
   SetLength(buf,0);
   Exit;
 end;

 p := @buf[0];

 SetLength(Names,1);
 SetLength(Params,1);

 for i := 0 to Length(Buf)-2 do
 begin
   if buf[i]="=" then
   begin
     SetLength(Names[Length(Names)-1],@buf[i]-p);
     Move(p^,Names[Length(Names)-1][1],@buf[i]-p);
     p := Pointer(Cardinal(@buf[i])+1);
     SetLength(Names,Length(Names)+1);
     Continue;
   end;

   if buf[i]=#0 then
   begin
     SetLength(Params[Length(Params)-1],@buf[i]-p);
     Move(p^,Params[Length(Params)-1][1],@buf[i]-p);
     SetLength(Params,Length(Params)+1);
     p := Pointer(Cardinal(@buf[i])+1);
     if buf[i+1]=#0 then break;
   end;
 end;

 SetLength(buf,0);

 for i := 0 to Length(Names)-1 do AddRecToFParams(Names[i],Params[i]);
 SetLength(Names,0);
 SetLength(Params,0);
end;

function TSettings.FGetParam(aNameValue: String):Variant;
var
 i: Integer;
begin
 Result := Variant(0);
 for i := 0 to Length(FParams)-1 do
 begin
   if FParams[i].rNameValue=aNameValue then
   begin
     Result := FParams[i].rParamData;
     break;
   end;
 end;
end;

procedure TSettings.FSetParam(aNameValue: String;aValue: Variant);
var
 i: Cardinal;
 isFound: Boolean;
 Rec: TRecParam;
 StrParam: String;
 Ret: Boolean;
begin
 isFound := False;
 for i := 0 to Length(FParams)-1 do
 begin
   if FParams[i].rNameValue=aNameValue then
   begin
     isFound := True;
     FParams[i].rParamData := aValue;
     Rec := FParams[i];
     break;
   end;
 end;

 if not isFound then
 begin
   AddRecToFParams(aNameValue,aValue);
   Rec := FParams[Length(FParams)-1];
 end;
 StrParam := Rec.rParamData;
 if StrParam="" then
   Ret := WritePrivateProfileString(PChar(FSectionName),
                                  Rec.rNameValue,
                                  nil,
                                  PChar(FIniName))
                else
   Ret := WritePrivateProfileString(PChar(FSectionName),
                                  Rec.rNameValue,
                                  PChar(StrParam),
                                  PChar(FIniName));

 if not Ret then
   raise Exception.Create("TSettings: Error. Value not saved");

end;

initialization
 AppSettings := TSettings.Create;
finalization
 AppSettings.Free;
end.


 
Игорь Шевченко ©   (2004-04-09 22:08) [76]

panov ©   (09.04.04 21:47)

1) Зачем так сложно ?

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

Пути решения ?


 
Игорь Шевченко ©   (2004-04-09 22:15) [77]


>  if FIniName = "" then


if aIniName = "" then


 
panov ©   (2004-04-09 22:17) [78]

>Игорь Шевченко ©   (09.04.04 22:08) [76]
При написании этого класса я не рассчитывал на БД.
Потому и решение было таким.

а для поставленной задачи решение может быть таким:

1. В БД хранятся параметры, общие для всех, параметры по умолчанию(шаблоны) - те, которые пользователи хранят в реестре локально.
Те настройки, которые не изменяются, редактирует только администратор.

2. Далее принцип такой же, как мне кажется.


 
panov ©   (2004-04-09 22:19) [79]

>Игорь Шевченко ©   (09.04.04 22:15) [77]

Точна! Первый жук-)


 
Германн ©   (2004-04-09 22:36) [80]

Раз глобальные переменные существуют, должен же из кто-то использовать.
© Писатель в детской курточке.



Страницы: 1 2 3 вся ветка

Текущий архив: 2004.05.02;
Скачать: CL | DM;

Наверх




Память: 0.67 MB
Время: 0.036 c
3-1080886816
Patrick
2004-04-02 10:20
2004.05.02
Упаковка данных.


14-1081431110
menart
2004-04-08 17:31
2004.05.02
Закат империи янки


1-1082105019
тихий вовочка
2004-04-16 12:43
2004.05.02
Глупый вопрос об обработке сообщений


14-1081421569
Igor_thief
2004-04-08 14:52
2004.05.02
Currency


14-1081419130
cs
2004-04-08 14:12
2004.05.02
Вопрос про карманный ПК