السلام عليكم ورحمة الله
قد نحتاج في حالات كثيرة زمن التشغيل إلى استخدام سلسلة من الكائنات ديناميكا
الجداول الثابتة Static Array أو الديناميكية قد تفي بالغرض في حالات ضيقة
لكن لاستخدامات أوسع: الحذف، الترتيب، المقارنة، البحث، الدمج... ينبغي برمجة ذلك يدويا
لنفكر لتوجه غرضي، البديل استخدام TList المعرف في المكتبة Classes.pas
يمثل سلسلة من الكائنات TObject فهو بذلك نمط مرن
وبالتالي باستخدام القولبة يمكنك توظيفه لأي كائن آخر
لتستفيد من الخصائص التقليدية للسلاسل المتصلة Exchange, Expand, Extract, First, IndexOf, Insert, Last, Move ,Remove, Pack, Sort, Capacity, Count, Items وغيرها...
طبعا دون إعادة كتابة الخوارزميات الجاهزة يكفي إعادة توريثها
مثال TIntegerList مصغرة:
تتمة الكود في المرفق IntList.rar
عند استخدامه مع أصناف أخرى يستحسن عدم توريثه مباشرة
وإلا قد تجبر مستخدمه على القولبة عند كل استخدام
TList خفيف ويصلح مع الأنماط الصغيرة
عند التعامل مع صنفيات أكثر أهمية (مثل المكونات)
أو تحتاج إلى استخدامات متقدمة
يمكنك الاستفادة من خدمات المكتبة Contnrs.pas المرفقة مع دلفي (إصدار >= 5 على الأقل)
باختصار:
TCollection وTCollectionItem تصميم رائع يختصر الكثير من العمل
يسمح هذان الصنفان بتجسيد العلاقة واحد إلى متعدد بين أصناف دلفي
كيف ذلك؟
لنشاهد المثال الآتي: نرغب بإنشاء صنفين "عامل" TEmployee و"مجموعة عمال" TEmployees
عامل واحد يمثل هنا غرض من TCollectionItem
في حين تمثل مجموعة العمال بالصنف TCollection
انسى أمر الـ Implementation، لنشاهد الاستخدام
الآن، لن نستخدم الصنف TEmployee (إلا مرة واحدة عند الإنشاء) لن نتعامل مع "عامل" واحد
بل سنقوم بإنشاء كائن من مجموعة العمال TEmployees ونخبره بالصنف الذي سنستخدمه كعنصر Item
كل ما نحن بحاجة إليه موجود في الصنف TEmployees، للإضافة Add وDelete للحذف وغيرهما...
مثال:
وما الذي سنستفيد من كل ذلك؟
الصنف TCollection مشتق من الصنف TPersistent وبذلك تستفيد من كل ما يوفره من Assign، التدفقات Streaming، وOwnership إذا أضفنا TOwnedCollection...
وسنختزل الكثير من الوقت مقارنة بما لو كتبنا ذلك من الصفر...
صممت هذه الأنماط لأجل برمجة المكونات وهي مناسبة جدا لها:
معظم مكونات دلفي تستخدم هذه الأنماط TActionListItem، TListColumn، TColumn...
أنماط أخرى أسهل من هذه؟
TObjectList أسهل من حيث التعامل
تنطلق من TList ولا تختلف عنها كثيرا
لتضيف ميزة رائعة وهي تدمير تلقائي للأغراض المضافة (مع ضبط OwnsObjects = True وهي كذلك افتراضيا)، مثال: لنفترض الصنف TPerson له خاصية FullName ترفق له عند الإنشاء، نكتب:
بعض إصدارات دلفي تحوي أخطاء بخصوص تسيير الذاكرة يستحسن التحقق منها ReportMemoryLeaksOnShutdown أو مكتبات خارجية أو غير ذلك...
بقيت TClassList التي تمثل TList لتسيير صنف من الأصناف TClass = class of TObject
أما TComponentList فتشتق من TObjectList لتضيف إمكانية التحديث التلقائي عند حذف العناصر وتحرير الذاكرة عند التدمير...
كود الأمثلة السابقة في المرفق CollectionsExample.rar
هذا مثال أأكد من خلاله أنه إذا عرفنا فقط كيف نستخدم ما بأيدينا من مكتبات دون اللجوء إلى المكونات الإضافية أو البحث في النت، لاختصرنا الكثير من الوقت والجهد مع تحقيق نتائج أفضل. أليس كذلك
بالتوفيق.
قد نحتاج في حالات كثيرة زمن التشغيل إلى استخدام سلسلة من الكائنات ديناميكا
الجداول الثابتة Static Array أو الديناميكية قد تفي بالغرض في حالات ضيقة
لكن لاستخدامات أوسع: الحذف، الترتيب، المقارنة، البحث، الدمج... ينبغي برمجة ذلك يدويا
لنفكر لتوجه غرضي، البديل استخدام TList المعرف في المكتبة Classes.pas
يمثل سلسلة من الكائنات TObject فهو بذلك نمط مرن
وبالتالي باستخدام القولبة يمكنك توظيفه لأي كائن آخر
لتستفيد من الخصائص التقليدية للسلاسل المتصلة Exchange, Expand, Extract, First, IndexOf, Insert, Last, Move ,Remove, Pack, Sort, Capacity, Count, Items وغيرها...
طبعا دون إعادة كتابة الخوارزميات الجاهزة يكفي إعادة توريثها
مثال TIntegerList مصغرة:
PHP كود :
type
TIntegerList = class(TList)
private
function Get(Index: Integer): Integer;
...
function TIntegerList.Get(Index: Integer): Integer;
begin
Result := Integer(inherited Items[Index]);
end;
عند استخدامه مع أصناف أخرى يستحسن عدم توريثه مباشرة
وإلا قد تجبر مستخدمه على القولبة عند كل استخدام
PHP كود :
type
TMyList = class
private
FMyList: TList;//<-- Best practice
function GetItems(Index: Integer): TMyList;
procedure SetItems(Index: Integer; const Value: TMyList);
public
function Add(Item: TMyList): Integer;
property Items[Index: Integer]: TMyList read GetItems write SetItems; default;
end;
عند التعامل مع صنفيات أكثر أهمية (مثل المكونات)
أو تحتاج إلى استخدامات متقدمة
يمكنك الاستفادة من خدمات المكتبة Contnrs.pas المرفقة مع دلفي (إصدار >= 5 على الأقل)
كود :
TObjectList
TClassList
TComponentList
باختصار:
TCollection وTCollectionItem تصميم رائع يختصر الكثير من العمل
يسمح هذان الصنفان بتجسيد العلاقة واحد إلى متعدد بين أصناف دلفي
كيف ذلك؟
لنشاهد المثال الآتي: نرغب بإنشاء صنفين "عامل" TEmployee و"مجموعة عمال" TEmployees
عامل واحد يمثل هنا غرض من TCollectionItem
في حين تمثل مجموعة العمال بالصنف TCollection
PHP كود :
type
TEmployee = class(TCollectionItem)
private
FFirstName: string;
FAge: SmallInt;
procedure SetFirstName(const Value: string);
procedure SetAge(const Value: SmallInt);
public
property FirstName: string read FFirstName write SetFirstName;
property Age: SmallInt read FAge write SetAge;
end;
TEmployees = class(TCollection)
private
function GetItem(Index: Integer): TEmployee;
public
function Add: TEmployee;
property Items[Index: Integer]: TEmployee read GetItem; default;
end;
الآن، لن نستخدم الصنف TEmployee (إلا مرة واحدة عند الإنشاء) لن نتعامل مع "عامل" واحد
بل سنقوم بإنشاء كائن من مجموعة العمال TEmployees ونخبره بالصنف الذي سنستخدمه كعنصر Item
كود :
[color=black][COLOR="Red"]TEmployees[/color].Create([color=Blue]TEmployee[/color])[/COLOR]
مثال:
PHP كود :
var
Team: TEmployees;
Officer: TEmployee;
begin
Team := TEmployees.Create(TEmployee);
Officer := Team.Add;
Officer.FirstName := 'Mohamed';
Officer.Age := 35;
Writeln('Officer:');
with Team[0] do
Writeln('Name: ', FirstName, #13#10'Age: ', Age);
Team.Free;
الصنف TCollection مشتق من الصنف TPersistent وبذلك تستفيد من كل ما يوفره من Assign، التدفقات Streaming، وOwnership إذا أضفنا TOwnedCollection...
وسنختزل الكثير من الوقت مقارنة بما لو كتبنا ذلك من الصفر...
صممت هذه الأنماط لأجل برمجة المكونات وهي مناسبة جدا لها:
معظم مكونات دلفي تستخدم هذه الأنماط TActionListItem، TListColumn، TColumn...
أنماط أخرى أسهل من هذه؟
TObjectList أسهل من حيث التعامل
تنطلق من TList ولا تختلف عنها كثيرا
لتضيف ميزة رائعة وهي تدمير تلقائي للأغراض المضافة (مع ضبط OwnsObjects = True وهي كذلك افتراضيا)، مثال: لنفترض الصنف TPerson له خاصية FullName ترفق له عند الإنشاء، نكتب:
PHP كود :
type
TPersonList = class(TObjectList)
private
function GetItem(Index: Integer): TPerson;
procedure SetItem(Index: Integer; const Value: TPerson);
public
property Items[Index : Integer]: TPerson read GetItem write SetItem; default;
end;
...
with TPersonList.Create do begin//By default OwnsObjects = True
Add(TPerson.Create('Ahmed'));
Add(TPerson.Create('Said'));
for I := 0 to Count - 1 do
Writeln('Member: ', Items[I].FullName);
// Clear; //Free; <- XE!
end;
بقيت TClassList التي تمثل TList لتسيير صنف من الأصناف TClass = class of TObject
أما TComponentList فتشتق من TObjectList لتضيف إمكانية التحديث التلقائي عند حذف العناصر وتحرير الذاكرة عند التدمير...
كود الأمثلة السابقة في المرفق CollectionsExample.rar
هذا مثال أأكد من خلاله أنه إذا عرفنا فقط كيف نستخدم ما بأيدينا من مكتبات دون اللجوء إلى المكونات الإضافية أو البحث في النت، لاختصرنا الكثير من الوقت والجهد مع تحقيق نتائج أفضل. أليس كذلك
بالتوفيق.
اللهم احقن دماء المسلمين، لا تنسوهم بالدعاء...