Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2004.05.02;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.65 MB
Время: 0.036 c
1-1082207475
Rasa
2004-04-17 17:11
2004.05.02
Как изменить каретку в Memo?


1-1081858966
DinpuSik
2004-04-13 16:22
2004.05.02
Как с помощью кнопки открыть фильм????


1-1081762062
Bulgar
2004-04-12 13:27
2004.05.02
Создание компонента в Delphi 6


14-1081475220
niko4543
2004-04-09 05:47
2004.05.02
Компонент. Поиогите!!!!! пожайлуста Срочно!!!!!!!!!!!!!!!!!!!!!!!


14-1081695483
Ученик
2004-04-11 18:58
2004.05.02
Задача!





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский