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

Вниз

Не нравится мне мой код   Найти похожие ветки 

 
TUser ©   (2004-12-17 15:16) [0]

Есть предковые классы
 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, но не уверен, что это то, что мне надо. Какие есть соображения типа "переписать все нафик"?


 
Anatoly Podgoretsky ©   (2004-12-17 15:24) [1]

И мне твой код не нравится :-)


 
TUser ©   (2004-12-17 15:29) [2]


> Anatoly Podgoretsky ©   (17.12.04 15:24) [1]

Как это сделать не через j.опу?


 
Alexander Panov ©   (2004-12-17 15:33) [3]

Ты ж не привел пример нескольких наследников, чтобы увидеть, чем они различаются...


 
Digitman ©   (2004-12-17 15:35) [4]


> Как это сделать не через j.опу?


для этого нужно понять, как отличается, по твоей логике,  поведение  методов классов-наследников от одноименных (однотипных) методов класса-предка ..


 
Anatoly Podgoretsky ©   (2004-12-17 15:36) [5]

А что ты хочешь?


 
Anatoly Podgoretsky ©   (2004-12-17 15:37) [6]

И зачем тогда задаешь вопрос Не нравится мне мой код , ты уж задай правильный :-)
А так можно обсуждать только одно нравится или нет.


 
REA   (2004-12-17 15:39) [7]

Если вопрос о шаблонах, то в D2005 что-то есть, а в более ранних версиях можно сделать через Include.


 
TUser ©   (2004-12-17 17:05) [8]

Что мне надо? Динамический массив, который обладает такими св-вами:
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;
единственная разница в которых состоит в том, к какому типу приводится результат. Хотелось бы делать это "малой кровью" - например, прописав какое-нибудь св-во у наследников, и не переписывая методы базового класса. Вот так.


 
Alexander Panov ©   (2004-12-17 17:17) [9]

TUser ©   (17.12.04 17:05) [8]
тогда будет Differs from previous declaration.


Попробуй воспользоваться директивой overload ?


 
TUser ©   (2004-12-17 17:18) [10]


> Попробуй воспользоваться директивой overload ?

Так все равно придется прописывать реализацию этого метода. А этого хочется избежать ... если возможно, конечно.


 
tesseract   (2004-12-17 17:24) [11]

А почему бы вместо Array не использовать Tlist?
И насчёт наследников - Наследники могут вызывать методы родителей и любой класс-наследник можно трактовать как родителя через TypeCasting - Посмотри на реализацию Tfield  и его наследников - и методы TField типа AsInteger. Или на замечательный тип Tstrings - он в VCL используется обширно


 
TUser ©   (2004-12-17 17:31) [12]

Это и есть почти TList, только еще добавлен контроль типов и автоматическое создание/удаление объектов, на которые храняться ссылки.
Хочу именно избежать переписывания методов. В идеале написать что-нибудь типа
TDesc = class(TDynArray)
FNeededType: {здесь написать требуемый тип}
end;
и все. Чтобы после этого наследник стал работаь с объектами только указанного типа.


 
GuAV ©   (2004-12-17 22:19) [13]

2 TUser ©  
IMHO один класс для списка и оператор as (или даже явное привидение типов) в зависимости от типа элемента уже по месту использования класса.


 
GuAV ©   (2004-12-17 22:20) [14]

А лучше ничего не придумаешь. IMHO.


 
Almaz ©   (2004-12-18 07:34) [15]


> Т.е. в приведенном коде это как раз и реализовано, но получается
> дофига почти одинаковых процедур типа
> 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);


Удачи.


 
TUser ©   (2004-12-18 11:56) [16]


> GuAV ©   (17.12.04 22:20) [14]
> Almaz ©   (18.12.04 07:34) [15]

Нет. Это еще хуже получится - везде, где используется объект такого класса писать TDynN(...). Уж лучше один модуль с неск. десятками почти одинаковых методов. Жаль, но видимо, лучше действительно ничего не придумать.
Всем спасибо.


 
Kolan ©   (2004-12-18 14:50) [17]

могу по оформлению замечания сделать :)

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 14:55) [18]


> Kolan ©   (18.12.04 14:50) [17]

Да, мне это каждый раз говорят, когда я свой код выкладываю. А я привык к wr и r. Во всех программах у меня так, и нормально. Должен же я быть хоть в чем-то оригинален.

> Переменных состояших из одной буквы следует избегать или
> писать с большой буквы.

Также следует избегать операторных скобок из одной буквы - наверное поэтому я и пишу на паскале. :))

> и пробелы.

Это на Бейсике.


 
Kolan ©   (2004-12-18 15:12) [19]

Я вообше 2 месяца назад писал так
funtion Get_Root_Dir(): integer;
О отступах даже не знал. Потом прочитал "Стандарты стилевого оформления фирмы Borland", кажись так называлась. Так там почти сразу написанно. -Переходите сразу на правильное оформление и вы оч. быстро привыкните и точно за 1 маленmre. программу привык. :)

> Также следует избегать операторных скобок из одной буквы

Как это?


> Должен же я быть хоть в чем-то оригинален.

Это да. Я почти все модули и классы я называю с буквы K.
:)


 
TUser ©   (2004-12-18 15:30) [20]


> > Также следует избегать операторных скобок из одной буквы
>
> Как это?

Я просто хотел сказать, что аргументация против переменных из одной буквы, мне кажется слабой. Таким же образом я могу доказать, что Паскать в 3-5 раз круче, чем Си.


 
begin...end ©   (2004-12-18 15:34) [21]

> [20] TUser ©   (18.12.04 15:30)

> Таким же образом я могу доказать, что Паскать в 3-5 раз
> круче, чем Си.

Доказательства не требуются, т.к. это очевидно :-)



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

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

Наверх




Память: 0.53 MB
Время: 0.027 c
14-1102785382
-=Iton=-
2004-12-11 20:16
2005.01.02
Java + БД


8-1096546874
Expl
2004-09-30 16:21
2005.01.02
Вывод на 2 канала звуки разной частоты


11-1084644178
Константин
2004-05-15 22:02
2005.01.02
Где достать "exptIntf.dcu" для Delphi? (или пришлите)


1-1103224643
Torin
2004-12-16 22:17
2005.01.02
Видимость компонента


1-1103116807
kolos_rus
2004-12-15 16:20
2005.01.02
Как узнать первую и последнюю дату месяца