想要设计一个通用的环行缓冲区管理器对象来管理不同的Record类型的数据,应该怎样写?(100分)

  • 主题发起人 主题发起人 littlefat
  • 开始时间 开始时间
L

littlefat

Unregistered / Unconfirmed
GUEST, unregistred user!
有两种记录类型:
TPoint=record
Counter:Integer;
Value:Byte;
end;

TPeak=record
Counter:Integer;
Value:Byte;
Width:Integer;
end;

这两种记录类型的数据,都需要一个环行缓冲管理器来管理,该环行缓冲区管理器要实现的一些功能完全相同。为了减少代码重复(提高代码复用率并减少差错),应该只设计一个通用的环行缓冲区管理类,可是我不知道应该怎样来设计这个类,所以现在万不得已,只能编下面的重复代码,希望高手指点我怎样才能写出这个通用类:

TRingBufferA=class(TObject)
private
FBuffer:Array [0..1024] of TPoint;
...
public
property Current:TPoint read GetCurrent;
property Last:TPoint read GetLast;
property Item[ItemIndex:Integer]:TPoint read GetItem;default;
function Add(APoint:TPoint):Integer;
end;

TRingBufferB=class(TObject)
private
FBuffer:Array [0..1024] of TPeak;
...
public
property Current:TPeak read GetCurrent;
property Last:TPeak read GetLast;
property Item[ItemIndex:Integer]:TPeak read GetItem;default;
function Add(APeak:TPeak):Integer;
end;


附带还有另外一个问题也让我比较难受,下面的语句编译不通过:
RingBufferA[3].Value:=50;
编译器报告说左边不能被赋值,现在我变通的办法是,将类中的代码:
property Item[ItemIndex:Integer]:TPeak read GetItem;default;
改成:
property Item[ItemIndex:Integer]:TPeak read GetItem write SetItem;default
...
TRingBufferA.SetItem(ItemIndex: Integer
const APoint: TPoint);
begin
Buffer[ItemIndex].Counter:=APoint.Counter;
Buffer[ItemIndex].Value:=APoint.Value;
end;

真的就不能直接赋值吗?

谢谢!
 
可以参考对象池的思想,不知道说的对不对,你可以找些资料看看。
 
有一个很简单的办法,定义成变体记录就好了:



TRecordType=(PointRec,PeakRec);

TMyRecord=Record
Counter:integer;
Value:Byte;
case RecordType:TRecordType of
PointRec:();
PeakRec:(Width:integer)
end;
 
小的愚钝,韦剑兄是否可以详细些?

我在实际使用中,至少要开两个RingBuffer,每个管一种类型的记录,可是我在使用中如何区分record的类型呢?
 
能否把你的类型改变一下了
procedure TForm1.FormCreate(Sender: TObject);
type
TNewPoint=packed record
count:integer;
value:byte;
end;
TNewRecord=record
case integer of
0:(count:integer;value:byte);
1:(NewPoint:TNewPoint;Width:integer);
end;
var
NR:TNewRecord;
r:TRect;
begin

end;
说晚了
 
我感觉用变体类型似乎不是最佳方案,另外,我在这里提问,已经把问题大大简化了,实际上我要管理的两个record类型的数据,其结构差别很大,大小也相差悬殊。。。。

不过还是谢谢楼上,但是我还是不知道在实际运用中,变体记录如何使用。。。[:(]
 
==================================
TRecordType=(PointRec,PeakRec);

TMyRecord=Record
Counter:integer;
Value:Byte;
case RecordType:TRecordType of
PointRec:();
PeakRec:(Width:integer)
end;
====================================
To littlefat:
在变体记录里面,case xxx:xxx of这个域就是变体的标记域。变体记录通过这个标记域的值来判断当前记录使用哪一种变体。

因此实际使用时是这样的,两个缓冲区都使用TMyRecord数据结构作为缓冲单元的数据类型。然后通过具体设置每个缓冲区单元RecordType域的值来区分不同的变体记录域,当给RecordType:=PointRec时,该缓冲区单元只有Counter和Value这两个数据域可以使用;当给RecordType:=PeakRec时,该缓冲区单元有Counter、Value和Width三个数据域可以使用。
 
PCircleItem = ^TCircleItem;
TCircleItem = record
Size: Integer;
Data: Pointer;
Prev: PCircleItem;
Next: PCircleItem;
end;

PPoint = ^TPoint;
TPoint=record
Counter:Integer;
Value:Byte;
end;

PPeak = ^TPeak;
TPeak=record
Counter:Integer;
Value:Byte;
Width:Integer;
end;

TRingBuffer=class(TObject)
private
FCircleItem: PCircleItem

...
public
property Current:PCircleItem read GetCurrent;
property Last:PCircleItem read GetLast;
property Item[ItemIndex:Integer]:PCircleItem read GetItem;default;
function Add(APoint:TPoint):Pointer
overload;
function Add(APeak: TPeak): Pointer
overload;
function Extract(CurrentCircleItem: PCircleItem): PCircleItem;
procedure Remove(CurrentCircleItem: PCircleItem);
end;

Example

function Add(APoint:TPoint):Pointer;
var
BPoint: PPoint;
NewCircleItem: PCircleItem;
begin
New(NewCircleItem);
NewCircleItem^.Size := SizeOf(APoint);//Size可判断究竟是TPoint还是TPeak类型(只要两个类型的大小不一致就可以,如果是一致的,那么这里改成常量定义,比如,1表示TPoint,2表示TPeak
New(BPoint);
BPoint^.Counter := APoint.Counter;
BPoint^.Value := APoint.Value;
NewCircleItem^.Data := BPoint;
NewCircleItem^.Prev := Last;
NewCircleItem^.Next := Last^.Next;
Last.^Next := NewCircleItem;
Result := NewCircleItem;
end;

function Add(APeak: TPeak): Pointer;
var
BPeak: PPeak;
NewCircleItem: PCircleItem;
begin
New(NewCircleItem);
NewCircleItem^.Size := SizeOf(APeak)

New(BPeak);
BPeak^.Counter := APeak.Counter;
BPeak^.Value := APeak.Value;
BPeak^.Width := APeak.Width;
NewCircleItem^.Data := BPeak;
NewCircleItem^.Prev := Last;
NewCircleItem^.Next := Last^.Next;
Last.^Next := NewCircleItem;
Result := NewCircleItem;
end;
 
给分,尽管我最终还是没用上。。。
 
多人接受答案了。
 
后退
顶部