VCL 프로젝트의 현대화를 위해 만들어진 GOF 명령 패턴의 단순화 된 버전. 또한이 프로젝트에 Action Factory를 추가했으며,이 프로젝트는 VCL 작업에 명령을 마무리하고 있습니다.

이 프로젝트에는 패턴 구현의 두 가지 버전이 포함되어 있습니다.
ICommand 인터페이스의 클래식 갱TCommand 클래스 TCommand 구성 요소는 레거시 VCL 코드의 현대화를 돕기 위해 만들어졌습니다. 그것은 얽힌 코드의 추출을 지원하는데, 단위 테스트를 통해 그것을 확보 한 후 객체 지향 코드를 유지하기 위해 클리너와 저렴하게 리팩토링 될 수 있습니다.
TCommand 구성 요소는 추출 된 코드를 지우고 UI 종속성을 제거한 후 리팩토링 해야하는 전환 객체입니다.

TCommand 구성 요소를 사용하는 가장 쉬운 방법은 새 클래스를 생성하고 긴 메소드를 실행 메소드에 붙여 넣고 모든 종속성을 게시 한 속성으로 추가하는 것입니다. 샘플 벨로우를 참조하십시오.
VCL 응용 프로그램의 TCOMMAND 사용 다이어그램 :

새로운 명령을 구축하려면 개발자는 TCommand (Unit : Pattern.Command.pas )에서 파생 된 새로운 클래스를 정의하고 주요 명령 로직을 포함하는 보호 된 방법 DoExecute 구현해야합니다.
개발자는 DoGuard 를 구현할 수 있으며, 이는 DoExecute 전에 호출되어 모든 필수 주입을 확인할 수 있습니다 (주입 시스템은 Bellow에 설명되어 있음). 일반적으로 모든 주사는 Assert Call과 함께 확인됩니다.
주입없이 샘플 명령 (빈 가드) :
type
TDiceRollCommand = class (TCommand)
protected
procedure DoExecute ; override;
end ;
procedure TDiceRollCommand.DoExecute ;
begin
ShowMessage( ' Dice roll: ' +RandomRange( 1 , 6 ).ToString);
end ; 명령을 실행하려면 객체를 생성하고 DoGuard Execute Public Method를 작성해야 DoExecute .
cmd := TDiceRollCommand.Ceate(Self);
cmd.Execute; TCommand 구성 요소는 IDE Form Designer (Object Inspector)가 사용하는 클래식 RTTI 메커니즘을 기반으로 자동화 된 주입 시스템을 구축했습니다. 주입 가능에 노출 된 속성은 구성 요소 (명령)의 published 섹션에서 정의되어야합니다. 모든 구성 요소 기반 클래스는 컴파일 프로세스 중 런타임 유형 정보 생성을 전환했습니다 (컴파일러 옵션 {$TYPEINFO ON} ). 새로운 명령을 만들 때 감사의 말을 전합니다. 모든 종속성을 쉽게 제공하고 게시 된 속성에 자동으로 할당 할 수 있습니다. 클래식 RTTI 엔진에 대한 자세한 내용은 델파이 문서 : 런타임 유형 정보를 참조하십시오.
두 개의 종속성이있는 샘플 명령 (하나는 필요하고 하나는 선택 사항) :
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 PANTERT)은보다 구성 요소 기반 접근법입니다. 이 패턴은 큰 응용 프로그램의 중요한 부분을 빠르게 추출하고 실행할 수있는 전환 단계와 비슷합니다. 이 과정의 최종 목표 지점은 최고의 아키텍처 솔루션이며 생성자를 통한 주입을 의미하고 객체 대신 인터페이스를 사용합니다.
TCommand.AdhocExecute<T> - 명령을 실행합니다 (명령을 작성하고 종속성을 주입하고 제거하고 제거)InjectExecute 와 함께 명령을 실행하십시오TCommandAction 빌드TCommandAction 클래스는 클래식 VCL 액션입니다 명령으로 추출 된 비즈니스 로직은 별도의 배경 스레드로 처리 된 비동기 명령으로 쉽게 변환 할 수 있습니다. TAsyncCommand 로 TCommand 클래스를 교체하는 것은 먼저 그러한 변환에서 가파른다.
uses
Pattern.AsyncCommand;
type
TAsyncDiceRollCommand = class (TAsyncCommand)
...
end ; 변화는 매우 간단하지만 일반적으로 다중 스레드 처리는 훨씬 더 심각한 주제 이며이 영역에 대한 더 깊은 지식이 필요합니다. 이 예제 ( TDiceRollCommand )에서 두 가지 주제는 문제가 있습니다.
fProgressBar: TProgressBarfOutputRolls: TStrings당신은 그것들을 쉽게 처리 할 수 있지만, 이것은보다 일반적인 멀티 스레드 처리 지식이 필요합니다. 전용 문서에서 찾을 수있는 자세한 정보 : 비동기 명령
TCommandAction 은 TAction 기반으로 한 래퍼 클래스이며 TCommand 클래스를 기반으로 명령을 실행할 수 있습니다. VCL 애플리케이션을 구축 할 때 개발자는이 동작이 많은 컨트롤 (작업에 의해 주도되거나 행동 인식 인 시각적 구성 요소)에 쉽게 바인딩 할 수 있습니다. 예를 들어 TCheckBox 에는 사용될 때 실행되는 Action 속성이 있습니다 (확인란) 상태 (확인). 조치에는 알림 시스템 빌드, 정확히 두 개의 엔진과 같은 다른 장점이 있습니다. 하나는 시각적 상태를 업데이트하고 다른 하나는 기존 구성 요소의 새롭고 삭제에 대해 알리기위한 더 내부적입니다. 두 엔진 모두이 섹션에서 설명하기에는 너무 복잡하므로 자세한 정보는 Delphi Online 문서에서 찾을 수 있습니다.
형태 아키텍처 관점 TCommandAction Invoker Object로 사용될 수 있으며 마이그레이션 후보다 탄성적 인 사용자 정의 솔루션으로 대체 할 수 있습니다.
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) | 명령이 완료되면 이벤트가 트리거됩니다 |
TCommandAction 의 샘플 설정 onupdate 이벤트 :
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 메소드를 통해 이루어져야합니다. Spring4D GlobalContainer 메소드와 같은 DI 컨테이너를 사용하여 구성된 객체를 만들어야합니다.
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 ;