نسخة مبسطة من نمط أمر GOF ، الذي تم إنشاؤه لأغراض تحديث مشاريع VCL. أضاف أيضًا Action Factory إلى هذا المشروع ، الذي يلف أمرًا في إجراء VCL.

يحتوي المشروع على نسختين من تنفيذ النمط:
ICommandTCommand تعتمد على TComponent تم إنشاء مكون TCommand للمساعدة في تحديث رمز VCL القديم . ويساعد على استخراج الكود المتشابك ، والذي يمكن إعادة تصميمه بعد تأمينه مع اختبارات الوحدة ، إلى أنظف وأرخص للحفاظ على الكود الموجهة للكائنات.
مكون TCommand هو كائن انتقالي يجب إعادة تمهيده بعد مسح الكود المستخرج وبعد إزالة تبعيات واجهة المستخدم

أسهل طريقة لاستخدام مكون TCommand هي إنشاء فئة جديدة ، وصق طريقة طويلة في طريقة تنفيذ وإضافة جميع التبعيات كخصائص منشورة. انظر عينة نوبة.
رسم تخطيطي لاستخدام TCommand في تطبيق VCL:

يحتاج المطور لبناء أمر جديد إلى تحديد فئة جديدة مشتقة من TCommand (الوحدة: Pattern.Command.pas ) وتنفيذ طريقة محمية DoExecute ، والتي تحتوي على منطق أمر رئيسي.
يمكن للمطور تنفيذ طريقة DoGuard أيضًا ، والتي تسمى قبل DoExecute والسماح بالتحقق من جميع الحقن الإلزامية (يتم شرح نظام الحقن). عادة ما يتم فحص جميع الحقن مع مكالمة التأكيد.
أمر عينة بدون حقن (حارس فارغ):
type
TDiceRollCommand = class (TCommand)
protected
procedure DoExecute ; override;
end ;
procedure TDiceRollCommand.DoExecute ;
begin
ShowMessage( ' Dice roll: ' +RandomRange( 1 , 6 ).ToString);
end ; لتنفيذ الأمر ، يجب عليك إنشاء كائن ودعوة Execute الطريقة العامة ، والتي تستدعي DoGuard ثم DoExecute :
cmd := TDiceRollCommand.Ceate(Self);
cmd.Execute; قام مكون TCommand بإنشاء نظام حقن آلي استنادًا إلى آلية RTTI الكلاسيكية التي يستخدمها مصمم نموذج IDE (مفتش الكائن). يجب تحديد الخصائص المعرضة للحقن في القسم published من المكون (الأمر). قامت جميع الفئات القائمة على المكونات بتشغيل توليد معلومات نوع التشغيل أثناء عملية التجميع (خيار برنامج التحويل البرمجي {$TYPEINFO ON} ). بفضل ذلك أثناء إنشاء أمر جديد ، يمكن توفير جميع التبعيات بسهولة وتعيينها على الخصائص المنشورة تلقائيًا. يمكن العثور على مزيد من المعلومات حول محرك RTTI الكلاسيكي في Delphi Documentation: معلومات نوع التشغيل
نموذج العينة مع اثنين من التبعية (واحد مطلوب وواحد اختياري):
type
TDiceRollCommand = class (TCommand)
const
RollCount = 100 ;
private
fOutput: TStrings;
fProgressBar: TProgressBar;
procedure ShowProgress (aRoll: integer);
protected
procedure DoGuard ; override;
procedure DoExecute ; override;
published
property OutputRolls: TStrings read fOutput
write fOutput;
property ProgressBar: TProgressBar read fProgressBar
write fProgressBar;
end ;
procedure TDiceRollCommand.DoGuard ;
begin
System.Assert(fOutput<> nil );
end ;
procedure TDiceRollCommand.ShowProgress (aRoll: integer);
begin
if Assigned(fProgressBar) then begin
if aRoll= 0 then
fProgressBar.Max := RollCount;
fProgressBar.Position := aRoll;
end ;
end
procedure TDiceRollCommand.DoExecute ;
begin
ShowProgress( 0 );
for var i := 0 to RollCount- 1 do
begin
fOutput.Add(RandomRange( 1 , 7 ).ToString);
ShowProgress(i+ 1 );
end ;
end ;تتم مطابقة الخصائص المنشورة المتاحة لـ TCommand مع أنواع المعلمات التي تم تمريرها في المعلمات (صفيف مفتوح). يتم استخدام القواعد التالية عن طريق مطابقة الخوارزمية:
تحذير! يتم الوصول إلى الكائن المحقن بواسطة العنوان في الذاكرة (المؤشر) ، وذلك بفضل أي تغييرات تم إجراؤها على الكائن مرئية داخل وخارج tcommand. يتم الوصول إلى الأنواع والسلاسل البسيطة من خلال القيمة ويجب تحديث الخصائص يدويًا ليتم تحديثها.
عينة من الكائنات حقن الكود لخصائص tdicerollCommand:
cmd := TDiceRollCommand.Create(Self)
.Inject([Memo1.Lines,ProgressBar1]);الطريقة الأكثر شعبية والمنصحة عادة لحقن التبعيات هي حقن مُنشئ. هذا الحل الذي تم تقديمه هنا (نمط TCommand) هو النهج القائم على المكونات. يشبه هذا النمط مرحلة انتقالية تسمح بسرعة باستخراج وتنفيذ أجزاء مهمة من التطبيق الكبير. النقطة المستهدفة النهائية في هذه العملية هي أفضل حل معماري ، تعني الحقن من خلال المنشئ واستخدام الواجهات بدلاً من الكائنات.
TCommand.AdhocExecute<T> - ينفذ الأمر (ينشئ أمرًا ، يتم تنفيذها في تبعيات الحقن ويتم إزالته)InjectExecuteTCommandAction الذي ينفذ الأمر عند استدعاء الإجراءTCommandAction فئة ASS Classic VCL يمكن تحويل منطق العمل ، الذي يتم استخلاصه في الأمر ، بسهولة إلى أمر غير متزامن ، معالجته في سلسلة خلفية منفصلة. يعد استبدال فئة TCommand مع TAsyncCommand أول شديدة الانحدار في هذا التحول:
uses
Pattern.AsyncCommand;
type
TAsyncDiceRollCommand = class (TAsyncCommand)
...
end ; على الرغم من أن التغيير بسيط للغاية ، ولكن بشكل عام ، فإن المعالجة المتعددة الخيوط هي موضوع أكثر خطورة وتتطلب معرفة أعمق بهذا المجال. في هذا المثال ( TDiceRollCommand ) موضوعان يمثلان مشكلة:
fProgressBar: TProgressBarfOutputRolls: TStringsيمكنك التعامل معهم بسهولة ، ولكن هذا يتطلب معرفة أكثر عمومية لمعالجة المعالجة. مزيد من المعلومات التي يمكنك العثور عليها في وثائق مخصصة: أمر غير متزامن
TCommandAction هي فئة غلاف تعتمد على TAction ويمكن أن تنفذ الأوامر بناءً على فئة TCommand . يمكن للمطور ، عند إنشاء تطبيق VCL ، ربط هذا الإجراء بسهولة بالعديد من عناصر التحكم (المكونات البصرية التي تحركها الإجراءات أو تدرك العمل). على سبيل المثال ، لدى TCheckBox خاصية Action التي يتم تنفيذها عند استخدامها وهي تغيير حالة مربع الاختيار (محدد). تتميز الإجراءات ببعض المزايا الأخرى مثل البناء في نظام الإخطار ، على وجه التحديد محركين من هذا القبيل: إحداها لتحديث الحالة البصرية وآخر ، أكثر داخليًا ، لإخطار إنشاء المكونات الجديدة والمكونات الحالية. كلا المحركين معقدين للغاية لا يمكن وصفهما في هذا القسم ، يمكن العثور على مزيد من المعلومات في وثائق Delphi Online.
البحث عن المنظور المعماري يمكن استخدام TCommandAction ككائن invoker وبعد أن يتم استبدال الترحيل بمزيد من حل مخصص مرن.
عينة بناء على TCommandAction Invoker:
Button1.Action := TCommandAction.Create(Button1)
.WithCaption( ' Run sample command ' )
.WithCommand(TSampleCommand.Create(Button1))
.WithInjections([Memo1, Edit1]);| طريقة المنفعة | وصف |
|---|---|
WithCaption(aCaption) | يضع تعليق عمل يتم عرضه في عنصر تحكم |
WithShortCut(aShortcut) | يضع اختصار يقوم بتنشيط إجراء |
WithCommand(aCommand) | يضع أمرًا للتنفيذ |
WithInjections(aInjections) | حقن القيم في خصائص الأمر |
WithEventOnUpdate(aProc) | تم تشغيل الحدث بعد حدث Action Onupdate |
WithEventAfterExecution(aProc) | حدث الحدث عند الانتهاء من الأمر |
عينة الإعداد الحدث Onupdate في TCommandAction :
Button2.Action := TCommandAction.Create(Self)
.WithCaption( ' Run sample command ' )
.WithCommand(MySampleCommand)
.WithEventOnUpdate(
procedure(cmd: TCommandAction)
begin
cmd.Enabled := CheckBox1.Checked;
end );يسمح نمط TCommand للمطورين باستخراج رمز الأعمال الثمين وجعل التطبيقات أقل اقترانًا. في الوقت نفسه ، لا يزال بإمكان المطورين استخدام ممارسات مكونات معروفة وتكوين رمز أكثر تعقيدًا باستخدام مكونات الأوامر. يمكن للمطورين حتى توسيع نمط القيادة مع خصائصهم وأحداثهم. ومع ذلك ، فإن هذا النهج هو حل مؤقت ويجب تطوره إلى تصميم أكثر موجهًا.
نمط TCommand متوافق مع نمط أمر GOF (انظر المخططات أعلاه) ويمكن تحديثه. يجب أن يبدأ هذا الاعتدال عند الانتهاء من مرحلة إعادة الطرد وسيتم تغطية المنطق عن طريق اختبارات الوحدة. أثناء إعادة إنشاء جميع التبعيات البصرية ، يجب إزالة جميع التبعيات غير ذات الصلة ، ويجب أن تنقسم الكود إلى طرق أو فئات أكثر منطقية.
بعد التحديث ، يجب حقن جميع التبعيات من خلال مُنشئ ، يجب الوصول إلى الأمر من خلال الواجهة ، وينبغي أن يكون الوصول إلى العناصر الداخلية الأوامر من خلال طرق Getter و Setter. يجب إنشاء كائنات مؤلفة باستخدام حاوية DI ، مثل طريقة Spring4D GlobalContainer .
تنفيذ الأوامر المخصصة (إنشاء ، حقن ، تنفيذ ، إزالة)
TCommand.AdhocExecute<TSampleCommand>([Memo1, Edit1]);يخلق تبعيات القيادة وحقن:
cmdSampleCommand := TSampleCommand.Create(AOwner);
cmdSampleCommand.Inject([Memo1, Edit1]); عينة مكون TCommand :
type
TSampleCommand = class (TCommand)
private
FMemo: TMemo;
FEdit: TEdit;
protected
procedure DoGuard ; override;
procedure DoExecute ; override;
published
property Memo: TMemo read FMemo write FMemo;
property Edit: TEdit read FEdit write FEdit;
end ;
procedure TSampleCommand.DoGuard ;
begin
System.Assert(Memo<> nil );
System.Assert(Edit<> nil );
end ;
procedure TSampleCommand.DoExecute ;
begin
Memo.Lines.Add( ' Getting Edit text and put it here ... ' );
Memo.Lines.Add( ' * Edit.Text: ' +Edit.Text);
end ;