Форум: "Потрепаться";
Текущий архив: 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