รูปแบบคำสั่ง GOF ที่ง่ายขึ้นซึ่งสร้างขึ้นเพื่อวัตถุประสงค์ในการปรับปรุงโครงการ VCL นอกจากนี้ยังได้เพิ่ม Action Factory ให้กับโครงการนี้ซึ่งเป็นการห่อคำสั่งลงในการดำเนินการ VCL

โครงการมีการใช้งานรูปแบบสองเวอร์ชัน:
ICommand icommandTCommand คลาสขึ้นอยู่กับ TComponent ส่วนประกอบของ TCommand ถูกสร้างขึ้นเพื่อช่วยให้ ทันสมัยของรหัส VCL เดิม มันช่วยให้การสกัดรหัสพันกันซึ่งหลังจากการทดสอบด้วยการทดสอบหน่วยสามารถ refactored เป็นทำความสะอาดและราคาถูกกว่าเพื่อรักษารหัสเชิงวัตถุ
องค์ประกอบ TCommand เป็นวัตถุการเปลี่ยนแปลงที่ควรได้รับการ refactored หลังจากล้างรหัสที่แยกออกมาและหลังจากลบการพึ่งพา UI

วิธีที่ง่ายที่สุดในการใช้ส่วนประกอบ 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 Component ได้สร้างระบบฉีดอัตโนมัติตามกลไก RTTI แบบคลาสสิกที่ใช้โดย IDE Form Designer (ผู้ตรวจสอบวัตถุ) คุณสมบัติที่สัมผัสได้ว่าต้องฉีดจะต้องกำหนดในส่วน published ขององค์ประกอบ (คำสั่ง) คลาสที่ใช้ส่วนประกอบทั้งหมดได้เปิดการสร้างข้อมูลประเภทรันไทม์ระหว่างกระบวนการรวบรวม (ตัวเลือกคอมไพเลอร์ {$TYPEINFO ON} ) ขอบคุณในระหว่างการสร้างคำสั่งใหม่การพึ่งพาทั้งหมดสามารถให้ได้อย่างง่ายดายและกำหนดให้กับคุณสมบัติที่เผยแพร่โดยอัตโนมัติ ข้อมูลเพิ่มเติมเกี่ยวกับเอ็นจิ้น RTTI แบบคลาสสิกสามารถหาได้ในเอกสาร Delphi: ข้อมูลประเภทรันไทม์
คำสั่งตัวอย่างที่มีสองการพึ่งพา (หนึ่งที่จำเป็นและหนึ่งทางเลือก):
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 นั้นถูกจับคู่กับประเภทของพารามิเตอร์ที่ส่งผ่านในพารามิเตอร์ (Open Array) กฎต่อไปนี้ใช้โดยอัลกอริทึมการจับคู่:
คำเตือน! วัตถุที่ฉีดจะเข้าถึงได้โดยที่อยู่ในหน่วยความจำ (ตัวชี้) ขอบคุณการเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นกับวัตถุสามารถมองเห็นได้ทั้งภายในและภายนอกของ TCommand ประเภทและสตริงที่ง่ายสามารถเข้าถึงได้ผ่านค่าและคุณสมบัติต้องอัปเดตด้วยตนเองเพื่ออัปเดต
ตัวอย่างรหัสการฉีดวัตถุไปยังคุณสมบัติของ tdicerollcommand:
cmd := TDiceRollCommand.Create(Self)
.Inject([Memo1.Lines,ProgressBar1]);วิธีการที่ได้รับความนิยมมากที่สุดและมักจะแนะนำในการฉีดพึ่งพาคือการฉีดคอนสตรัคเตอร์ โซลูชันนี้แนะนำที่นี่ (รูปแบบ tCommand) เป็นวิธีการตามองค์ประกอบมากขึ้น รูปแบบนี้เป็นเหมือนขั้นตอนการเปลี่ยนแปลงซึ่งอนุญาตให้แยกและดำเนินการส่วนสำคัญของแอปพลิเคชันขนาดใหญ่ได้อย่างรวดเร็ว จุดเป้าหมายสุดท้ายในกระบวนการนั้นเป็นวิธีการแก้ปัญหาทางสถาปัตยกรรมที่ดีที่สุดหมายถึงการฉีดผ่านตัวสร้างและใช้อินเทอร์เฟซแทนวัตถุ
TCommand.AdhocExecute<T> - ดำเนินการคำสั่ง (สร้างคำสั่ง, การพึ่งพาการฉีดยาดำเนินการและลบออก)Inject โทรExecuteTCommandAction ซึ่งดำเนินการคำสั่งเมื่อมีการเรียกใช้การกระทำTCommandAction เป็นแอ็คชั่น VCL แบบคลาสสิก ตรรกะทางธุรกิจที่สกัดลงในคำสั่งสามารถแปลงเป็นคำสั่งแบบอะซิงโครนัสได้อย่างง่ายดายประมวลผลในเธรดพื้นหลังแยกต่างหาก การแทนที่คลาส TCommand ด้วย TAsyncCommand เป็นครั้งแรกที่สูงชันในการเปลี่ยนแปลงดังกล่าว:
uses
Pattern.AsyncCommand;
type
TAsyncDiceRollCommand = class (TAsyncCommand)
...
end ; แม้ว่าการเปลี่ยนแปลงนั้นง่ายมาก แต่โดยทั่วไปแล้วการประมวลผลแบบหลายเธรดนั้นเป็นเรื่องที่จริงจังกว่าและต้องใช้ความรู้ที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับพื้นที่นี้ ในตัวอย่างนี้ ( TDiceRollCommand ) สองหัวข้อเป็นปัญหา:
fProgressBar: TProgressBarfOutputRolls: TStringsคุณสามารถจัดการกับพวกเขาได้อย่างง่ายดาย แต่สิ่งนี้ต้องการความรู้การประมวลผลแบบมัลติเธรดทั่วไปมากขึ้น ข้อมูลเพิ่มเติมที่คุณสามารถค้นหาได้ในเอกสารเฉพาะ: คำสั่งแบบอะซิงโครนัส
TCommandAction เป็นคลาส wrapper ตาม TAction และสามารถดำเนินการคำสั่งตามคลาส TCommand นักพัฒนาเมื่อสร้างแอปพลิเคชัน VCL สามารถผูกแอ็คชั่นนี้กับการควบคุมจำนวนมากได้อย่างง่ายดาย ตัวอย่างเช่น TCheckBox มีคุณสมบัติ Action ซึ่งดำเนินการเมื่อใช้กำลังเปลี่ยนสถานะช่องทำเครื่องหมาย (ตรวจสอบ) การกระทำมีข้อได้เปรียบอื่น ๆ เช่นการสร้างในระบบการแจ้งเตือนสองอย่างแม่นยำเอ็นจิ้นดังกล่าว: หนึ่งสำหรับการอัพเดทสถานะภาพและอื่น ๆ ภายในมากขึ้นเพื่อแจ้งเกี่ยวกับการสร้างใหม่และการลบส่วนประกอบที่มีอยู่ เครื่องยนต์ทั้งสองมีความซับซ้อนเกินกว่าที่จะอธิบายในส่วนนี้ข้อมูลเพิ่มเติมสามารถพบได้ในเอกสารออนไลน์ของ Delphi
การมองหามุมมองทางสถาปัตยกรรม 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) | เหตุการณ์ที่เกิดขึ้นหลังจากการดำเนินการ 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 (ดูไดอะแกรมด้านบน) และสามารถทันสมัย การกลั่นกรองนี้ควรเริ่มต้นเมื่อขั้นตอนการปรับโครงสร้างจะเสร็จสิ้นและตรรกะจะได้รับการคุ้มครองโดยการทดสอบหน่วย ในระหว่างการ refactoring การพึ่งพาภาพทั้งหมดควรถูกลบออกนอกจากนี้ยังมีการพึ่งพาที่ไม่เกี่ยวข้องทั้งหมดและรหัสควรแบ่งออกเป็นวิธีหรือคลาสที่มีเหตุผลมากขึ้น
หลังจากการปรับปรุงให้ทันสมัยการพึ่งพาทั้งหมดควรถูกฉีดผ่านตัวสร้างคำสั่งควรเข้าถึงผ่านอินเตอร์เฟสการเข้าถึงรายการภายในคำสั่งควรผ่านวิธี getter และ setter วัตถุที่แต่งขึ้นควรถูกสร้างขึ้นโดยใช้คอนเทนเนอร์ DI เช่นวิธี Spring4D GlobalContainer
การดำเนินการคำสั่ง ad-hoc (สร้าง, ฉีด, ดำเนินการ, ลบ)
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 ;