2016-07-04 5 views
1

나중에 다양한 작업을 수행하기 위해 다양한 형태의 애플리케이션 포인터를 유지해야하는 Delphi 유닛이 있습니다.Delphi : 순환 참조를 피하기 위해 변수 선언하기

이러한 작업을 수행하려면 포인터를 양식 유형 (ex.

var  
    ptrFrmMain: Pointer; 
    CurrentFrmMain: TfrmMain; 
begin 
    CurrentFrmMain := ptrFrmMain; 
    CurrentFrmMain.Close(); 
end; 

문제는이 장치가 애플리케이션의 모든 다른 델파이 유닛의 용도에 포함된다는 것이다. 그래서 간단하게 Pointer을 인터페이스 섹션에 선언 할 수는 있지만 다른 유닛 (예 : frmMain.pasTfrmMain)에 선언 된 타입을 선언 할 수는 없습니다.

나는 같은 구현 섹션에서 사용을 배치하여이 문제를 해결할 수 :

interface 
type TMyThread = class(TThread) 
    Public 
    ptrFrmMain:Pointer 
... 

implementation 
    uses frmMain 

    var 
     CurrentFrmMain: TfrmMain; 

하지만 문제는 여전히 존재 : 나는 멀티 스레드 목적을 위해, 내 클래스 인스턴스에 구체적으로 변수를 필요 일반 전역 변수가 아닙니다. TfrmMain은 선언되지 않았으므로 인터페이스 섹션을 사용할 수 없으므로 TmyThread 클래스에 배치 할 수 없습니다.

솔루션을 사용하는 모든 절차에서 로컬 변수로 CurrentFrmMain을 배치 한 다음 매번 CurrentFrmMain := ptrFrmMain 변환을 수행하지만 더 좋은 해결책을 알고 계십니까?

대단히 감사합니다.

+2

포인터를 내부 변환 할 수 있습니다 또는 일반 기본 TForm로 선언 할 수 있습니다 ... –

+0

@FreeConsulting 내 폼의 특정있는 함수를 호출해야하기 때문에 일반 기본 Tform으로 선언 할 수 없습니다. 'CurrentFrmMain.MyFunction()' – Flavio

+0

@FreeConsulting 또한 포인터를 내부에 캐스팅하는 것은 위에서 언급 한 해결책 이었지만 각 함수에서 다시 초기화하지 않는 것이 좋습니다. – Flavio

답변

6

나는 스레드에 Form 포인터를 전혀 넣지 않을 것입니다. 내가 대신 스레드 홀드 콜백 기능을 가지고, 또는 인터페이스 것 :

type 
    TCloseProc: procedure of object; 

    TMyThread = class(TThread) 
    public 
    CloseProc: TCloseProc; 
    ... 
    end; 

... 

begin 
    if Assigned(CloseProc) then CloseProc(); 
end; 

스레드가 생성
type 
    IMyIntf = interface(IInterface) 
    ['{9CC7DB9E-D47F-4B7D-BBF9-6E9B80823086}'] 
    procedure DoClose; 
    end; 

    TMyThread = class(TThread) 
    public 
    Intf: IMyIntf; 
    ... 
    end; 

... 

begin 
    if Assigned(Intf) then Intf.DoClose(); 
end; 

... 

type 
    TfrmMain = class(TForm, IMyIntf) 
    public 
    procedure doClose; 
    end; 

procedure TfrmMain.doClose; 
begin 
    Close; 
end; 

, 그 콜백에 양식 방법을 할당하거나 폼의 인터페이스 구현을 전달 스레드 :

Thread := TMyThread.Create(True); 
Thread.CloseProc := frmMain.Close; 
Thread.Resume; 

Thread := TMyThread.Create(True); 
Thread.Intf := frmMain as IMyIntf; 
Thread.Resume; 

어느 쪽이든 스레드는 양식 별 기능을 제공하면서 실제 Forms를 전혀 알 필요가 없습니다.

+0

인터페이스가 깔끔하지만 ARC 및 예상치 못한 자유 형식으로 인해 위험에 처하게되지는 않습니까? –

+0

양식의 주어진 객체가 필요한 인터페이스를 구현하는 경우에도 가드 검사가 추가 될 것으로 추측됩니다 .... –

+3

@ Arioch'The : 'TComponent'가 인터페이스의 참조 카운팅을 비활성화하기 때문에 ARC는 VCL에서 문제가되지 않습니다 'TForm'은 컴포넌트 객체에 의해 구현되며'TComponent' 자손입니다. 그리고'as '연산자는 인터페이스 구현에 필요한 검사를 제공합니다. –

3

"응용 프로그램의 다양한 형태의 포인터를 유지하고 나중에 작업을 수행하는 것"이 ​​무엇을 의미합니까? - 어떤 종류의 일 (또는 종류)입니까? 이것은 circular reference이나 다른 언어 관련 문제가 아닌 분해에 대한 일반적인 소프트웨어 설계에 대한 질문입니다.

모든 양식에서 동일한 작업을 수행하려는 경우 - 동일한 BASE-FORM-CLASS에서 양식을 파생시키고 특정 양식 클래스가 아닌 해당 기본 클래스에 대한 참조를 유지해야합니다. 예를 들어, 단지 .Release이 필요하다면 모두 모두 TForm 타입 참조로 유지할 수 있습니다. 이것은 일반적인 추상 인터페이스를 추출하는 전형적인 경우입니다.

TMyFormWithActions = class (TForm) .... end;  
TMyForm1234 = class (TMyFormWithActions) .... end; 
TMyFormABCD = class (TMyFormWithActions) .... end; 

는 또한하지의 중간 클래스에 공통 기능을 추출하지만, MS COM interface로 레미처럼 그의 대답에 표시 할 수 있습니다.그러나 이것은 매우 다른 메모리 모델 (ARC 하나)과 접하고 있습니다. TForm에 참조 카운팅을 자동 파괴한다고는 예상하지 않지만, 특히 상속 된 복잡한 응용 프로그램에서는이 문제가 발생할 수 없다고 완전히 확신 할 수는 없습니다. 그래서 저는 그러한 접근법을 좋아하지만, 때로는 실제로 예기치 못해서 조기에 사체가 죽을 수도 있기 때문에 생략했습니다. 그것이 가장 깨끗한 해결책 일지 모르지만 그것이 일어나지 않을 것이라는 것을 확신 할 수 있다면. 당신은 다른 작업을 수행해야하는 경우


이 그리고, 당신은 참으로 단순히 자신뿐만 아니라 행동, 소프트웨어 조각에 대한 형태에 대한 참조를 저장할 수 있습니다. 그런 다음 스레드 선언 클래스는 양식 및 프로 시저 데이터 셀을 유지하기위한 일반적인 프레임 워크를 작성합니다. 그런 다음 특정 작업을 구현하는 추가 단위를 전달해야합니다.

(스레드와 액션 인터페이스 장치) == uses ==> (TMyFormABCD 장치에 대한 작업) < == uses == (TMyFormABCD 형태 선언 장치)

간단한 옵션으로, 당신은 선언 할 수 있습니다 그 양식 자체와 동일한 단위의 행동. 그러면 모든 폼 - 단위가 쓰레드 단위에 의존하게 될 것이지만, 쓰레드 단위 (일반적이고 특정 형태에 독립적으로 재구성 됨)는 더 이상 폼 - 단위에 의존하지 않게됩니다. 아마도 그것은 "Inversion of control"이라고 불릴 것입니다. 윈도우 메시지를 사용하는 것 - http://www.uweraabe.de/Blog/2010/08/16/the-visitor-pattern-part-1/


그리고 또 하나 개의 방식은 그 방식을 모두 구현으로 볼 수있는이, 설계 :

이 시리즈를 참조하십시오. "공용 인터페이스"에서 "동작"은 사용자 지정 WM_xxx 메시지 (정수 const)로 표현됩니다. 그런 다음 해당 스레드는 PostMessage API를 사용하여 해당 동작을 양식에 알립니다. 그리고 그러한 형태 - 메시지를 다루는 방법을 구현함으로써 (또는 메시지를 무시하고 구현하지 않음으로써) 그러한 행동 구현을 제공 할 것입니다.

참조 : http://www.cryer.co.uk/brian/delphi/howto_send_custom_window_message.htm

PostMessage 외부 스레드에서 사용하지만 할 수 없습니다 (쉽게) 반환 값 될 수있다. SendMessage은 기본 Delphi 스레드에서만 사용할 수 있습니다. 또한 메시지를 게시하기 전에 MyTargetForm.HandleAllocated()인지 확인해야합니다.

+0

내 폼과 관련된 함수를 호출해야하기 때문에 일반 기본 Tform 클래스를 사용할 수 없습니다 (예 : 'CurrentFrmMain.MyFunction()'. 그래서 많은 양의 코드를 다시 작성하지 않고도이 함수를 쉽게 호출 할 수 있기를 바랍니다. (가능한 경우 CurrentFrmMain 변수를 클래스 멤버로 유지하고 로컬 변수로 사용할 필요가 없습니다. 포인터를 사용하는 각 함수에서 포인터로 다시 초기화해야 함). – Flavio

+0

"내 양식의 특정"- 구체적인 의도 (= 선언 = 인터페이스 = 계약) 또는 특정 구현 (일명 "가상 함수"및 "추상 함수")은 무엇을 의미합니까? –

+0

다른 양식을 통해 전혀 다른 행동을 원한다면 방문자 패턴 시퀀스를 읽으십시오. 한 발짝 물러나서 프로그램을 분해하는 방법에 대한 더 큰 그림을보아야합니다. 어떻게 그것의 블록을 디자인합니다. 어디에서 행동을 취할 것인가, 어디서 양식을 넣을 것인가. 몇 가지 가능한 방법이 있으며 모두 상충 관계가 있으며 프로그램 작업을 아는 것만이 덜 문제가되는 사항을 추측 할 수 있습니다. –