![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Не нравится мне мой код
TUser © (2004-12-17 15:16:00)Есть предковые классы
TDynElement = class
end;
TDynArray = class
private
FCount: integer;
FAutoIncrement: boolean;
FAutoCreate: boolean;
FArray: array of TDynElement;
procedure wrLength(Value:integer);
public
constructor Create;
destructor Destroy; override;
function rItems(Index:integer):TDynElement;
procedure wrItems(Index:integer; Value:TDynElement);
procedure CreateItem(Index:integer); virtual; abstract;
property Length:integer read FCount write wrLength;
property AutoIncrement:boolean read FAutoIncrement write FAutoIncrement default true;
property AutoCreate:boolean read FAutoCreate write FAutoCreate default true;
end;
и куча наследников (уже несколько десятков набралось)
TDyn1 = class(TDynElement)
public
{any properties to storage}
end;
TDyn1Array = class(TDynArray)
private
function rItems(Index:integer):TFound;
procedure wrItems(Index:integer; Value:TFound);
public
procedure CreateItem(Index:integer); override;
property Items[Index:integer]:TFound read rItems write wrItems; default;
end;
Реализауия такая
procedure TDynArray.wrLength(Value:integer);
var Power2: integer;
f:boolean;
begin
if Value < 0 then begin
PutInConsol('procedure TDynArray.wrLength(Value:integer);');
PutInConsol('Value = '+inttostr(Value));
end
else begin
if Value > system.length(FArray) then begin
f:=true; Power2:=512;
while f and (Power2 >= 8) do
if Value >= Power2 then
f:=false
else Power2 := Power2 div 2;
if f then Power2:=1;
if Value mod Power2 = 0 then
Power2:=Value
else
Power2:=(Value div Power2) * Power2 + Power2;
SetLength(FArray,Power2);
end;
FCount:=Value;
end;
end;
function TDynArray.rItems(Index:integer):TDynElement;
begin
if (Index < 0) or (Index >= FCount) then begin
PutInConsol('function TDynArray.rItems(Index:integer):pointer;');
PutInConsol('Index = '+inttostr(Index));
PutInConsol('FCount = '+inttostr(FCount));
end else begin
if FArray[Index] = nil then
if FAutoCreate then
CreateItem(Index);
result:=FArray[Index];
end;
end;
procedure TDynArray.wrItems(Index:integer; Value:TDynElement);
begin
if (Index < 0) or (Index >= FCount) then
if FAutoIncrement and (Index > 0) then
wrLength(Index+1)
else begin
PutInConsol('procedure TDynArray.wrItems(Index:integer; Value:pointer);');
PutInConsol('Index = '+inttostr(Index));
Exit; // :((
end;
FArray[Index]:=Value;
end;
constructor TDynArray.Create;
begin
inherited;
SetLength(FArray,0);
FCount:=0;
end;
destructor TDynArray.Destroy;
var i: integer;
begin
for i:=0 to system.length(FArray)-1 do
FArray[i].Free;
SetLength(FArray,0);
inherited;
end;
function TDyn1Array.rItems(Index:integer):TDyn1;
begin
result:=TDyn1(inherited rItems(Index));
end;
procedure TDyn1Array.wrItems(Index:integer; Value:TDyn1);
begin
inherited wrItems(Index,Value);
end;
procedure TDyn1Array.CreateItem(Index:integer);
begin
Items[Index]:=TDyn1.Create;
end;
Но когда уже есть TDyn1, ..., TDyn125, то складывается впечатление, что я изобретаю какую-то ерунду. Должен быть какой-нибудь способ, чтобы создать базывай класс, а в наследниках переписать тип для Items. Пробовал сclass of, но не уверен, что это то, что мне надо. Какие есть соображения типа 'переписать все нафик'?
begin...end (2004-12-18 15:34:00) [1]> [20] TUser © (18.12.04 15:30)
> Таким же образом я могу доказать, что Паскать в 3-5 раз
> круче, чем Си.
Доказательства не требуются, т.к. это очевидно :-)
TUser (2004-12-18 15:30:00) [2]
> > Также следует избегать операторных скобок из одной буквы
>
> Как это?
Я просто хотел сказать, что аргументация против переменных из одной буквы, мне кажется слабой. Таким же образом я могу доказать, что Паскать в 3-5 раз круче, чем Си.
Kolan (2004-12-18 15:12:00) [3]Я вообше 2 месяца назад писал так
funtion Get_Root_Dir(): integer;
О отступах даже не знал. Потом прочитал "Стандарты стилевого оформления фирмы Borland", кажись так называлась. Так там почти сразу написанно. -Переходите сразу на правильное оформление и вы оч. быстро привыкните и точно за 1 маленmre. программу привык. :)
> Также следует избегать операторных скобок из однойбуквы
Как это?
> Должен же я быть хоть в чем-то оригинален.
Это да. Я почти все модули и классы я называю с буквы K.
:)
TUser (2004-12-18 14:55:00) [4]
> Kolan © (18.12.04 14:50) [17]
Да, мне это каждый раз говорят, когда я свой код выкладываю. А я привык к wr и r. Во всех программах у меня так, и нормально. Должен же я быть хоть в чем-то оригинален.
> Переменных состояших из одной буквы следует избегать или
> писать с большой буквы.
Также следует избегать операторных скобок из одной буквы - наверное поэтому я и пишу на паскале. :))
> и пробелы.
Это на Бейсике.
Kolan (2004-12-18 14:50:00) [5]могу по оформлению замечания сделать :)
property Length:integer read FCount write wrLength;
property Length:integer read FCount write SetLength;
А если нада для read то будет GetLength...
wrLength - по моему это называется венгерская нотация её следует использовать для перечисляемого типа.
Например
TErrorType =
(
etUnKnownCommand // Не известная команда.
);
f:boolean;
Переменных состояших из одной буквы следует избегать или писать с большой буквы.
F: Boolean;
и пробелы.
I := I + 1;
:)))
TUser (2004-12-18 11:56:00) [6]
> GuAV © (17.12.04 22:20) [14]
> Almaz © (18.12.04 07:34) [15]
Нет. Это еще хуже получится - везде, где используется объект такого класса писать TDynN(...). Уж лучше один модуль с неск. десятками почти одинаковых методов. Жаль, но видимо, лучше действительно ничего не придумать.
Всем спасибо.
Almaz (2004-12-18 07:34:00) [7]
> Т.е. в приведенном коде это как раз и реализовано, но получается
> дофига почти одинаковых процедур типа
> function TDyn1Array.rItems(Index:integer):TDyn1;
> begin
> result:=TDyn1(inherited rItems(Index));
> end;
А почему это преобразование типа не выполнять в коде по месту приложения ? Т.е. там где надо писатьTDyn1(DynArray.rItems(I))?
Единственная проблема, котороя может возникнуть - это методCreateItemкоторый должен создавать элемент заданного типа, но это можно решить следующим образом:
type
TDynElement = class
end;
TDynElementClass = class of TDynElement;
TDynArray = class
private
FDynElementClass: TDynElementClass;
...
public
constructor Create(DynElementClass: TDynElementClass);
procedure CreateItem(Index:integer);
...
end;
constructor TDynArray.Create(DynElementClass: TDynElementClass);
begin
FDynElementClass := DynElementClass;
...
end;
procedure TDynArray.CreateItem(Index: Integer);
begin
Items[Index] := FDynElementClass.Create;
end;
...
DynArray := TDynArray.Create(TDyn1);
Удачи.
GuAV (2004-12-17 22:20:00) [8]А лучше ничего не придумаешь. IMHO.
GuAV (2004-12-17 22:19:00) [9]2 TUser ©
IMHO один класс для списка и оператор as (или даже явное привидение типов) в зависимости от типа элемента уже по месту использования класса.
TUser (2004-12-17 17:31:00) [10]Это и есть почти TList, только еще добавлен контроль типов и автоматическое создание/удаление объектов, на которые храняться ссылки.
Хочу именно избежать переписывания методов. В идеале написать что-нибудь типа
TDesc = class(TDynArray)
FNeededType: {здесь написать требуемый тип}
end;
и все. Чтобы после этого наследник стал работаь с объектами только указанного типа.
tesseract (2004-12-17 17:24:00) [11]А почему бы вместо Array не использовать Tlist?
И насчёт наследников - Наследники могут вызывать методы родителей и любой класс-наследник можно трактовать как родителя через TypeCasting - Посмотри на реализацию Tfield и его наследников - и методы TField типа AsInteger. Или на замечательный тип Tstrings - он в VCL используется обширно
TUser (2004-12-17 17:18:00) [12]
> Попробуй воспользоваться директивой overload ?
Так все равно придется прописывать реализацию этого метода. А этого хочется избежать ... если возможно, конечно.
Alexander Panov (2004-12-17 17:17:00) [13]TUser © (17.12.04 17:05) [8]
тогда будет Differs from previous declaration.
Попробуй воспользоваться директивой overload?
TUser (2004-12-17 17:05:00) [14]Что мне надо? Динамический массив, который обладает такими св-вами:
1. Умное выделение памяти - большими блоками (как в TList'е).
2. Несокращение размера после его укорачивания.
Эти пп. позволяют избежать большого кол-ва перераспределений памяти. Например, если сначала пришло 3 раза подряд запрос на 1 элемент - будет 3 раза выделено по элементу, если потом придет запрос на 25 элементов - будет выделено 32-3=29. Если потом попросить еще 2 элемента - то просто увеличится счетчик FCount. Если потом уменьшить длину на 10 - то опять же просто FCount изменится.
Также надо
3. Автоматическое создание и удаление объектов.
4. Контроль типов при добавлении элементов. Вот здесь и проблема. Для работы с каждым типом создаем своего наследника. Все типы, с которыми надо работать, - наследники TDynElement. Надо в наследниках реализовать методы wrItem и rItem таким образом, чтобы они принимали правильный (для данного наследника тип). Но не могу же я написать
procedure wrItem(Index:integer; Value:TDynElement); virtual;
...
TDyn1 = class(TDynElement)
...
procedure wrItem(Index:integer; Value:TDyn1); override;
...
тогда будет Differs from previous declaration. Подозреваю, что должен существовать какой-нибудь простой способ сделать что-то типа такого класса, у которого есть св-во Items[] с элементами типа TDynElement, а у его наследников методы доступа к этому полю работают не с TDynElement, а с наследниками TDynElement'а. Т.е. в приведенном коде это как раз и реализовано, но получается дофига почти одинаковых процедур типа
function TDyn1Array.rItems(Index:integer):TDyn1;
begin
result:=TDyn1(inherited rItems(Index));
end;
единственная разница в которых состоит в том, к какому типу приводится результат. Хотелось бы делать это 'малой кровью' - например, прописав какое-нибудь св-во у наследников, и не переписывая методы базового класса. Вот так.
REA (2004-12-17 15:39:00) [15]Если вопрос о шаблонах, то в D2005 что-то есть, а в более ранних версиях можно сделать через Include.
Anatoly Podgoretsky (2004-12-17 15:37:00) [16]И зачем тогда задаешь вопрос Не нравится мне мой код, ты уж задай правильный :-)
А так можно обсуждать только одно нравится или нет.
Anatoly Podgoretsky (2004-12-17 15:36:00) [17]А что ты хочешь?
Digitman (2004-12-17 15:35:00) [18]
> Как это сделать не через j.опу?
для этого нужно понять, как отличается, по твоей логике, поведение методов классов-наследников от одноименных (однотипных) методов класса-предка ..
Alexander Panov (2004-12-17 15:33:00) [19]Ты ж не привел пример нескольких наследников, чтобы увидеть, чем они различаются...
TUser (2004-12-17 15:29:00) [20]
> Anatoly Podgoretsky © (17.12.04 15:24) [1]
Как это сделать не через j.опу?