2012-06-19 5 views
6

डेल्फी में ऑब्जर्वर पैटर्न के अच्छे उदाहरण हैं, & स्टैक ओवरफ्लो, जैसे Best way to implement observer pattern in Delphi और Are there any Videos/Screen casts or other resources on how to use Interfaces in Delphi? पर सवालों के जवाब के लिए धन्यवाद। उन stackoverflow सवाल से, शिक्षाप्रद सामग्री के निम्नलिखित लिंक निकाले जाते हैं:डुबिट के DUnitWizard में निहित XPObserver इकाई का उपयोग कैसे करें, एक पर्यवेक्षक पैटर्न, या यहां तक ​​कि एक एमवीसी पैटर्न को लागू करने के लिए?

  1. Joanna Carter's blog

  2. SourceMaking site

  3. TDelphiHobbyist's blog

  4. itte.no site

  5. dunit's DUnitWizard

कि दूसरी stackoverflow सवाल में, mghie करीब से देख Worthing के रूप में dunit's DUnitWizard's XPObserver.pas के रूप में बहुत ही दिलचस्प और अन्य XP*.pas का वर्णन किया। हालांकि, XPObserver इकाई को केवल दो स्थानों पर संदर्भित किया गया है, dunit\Contrib\DUnitWizard\Source\Common\dunit\XPObserverTests.pas में जहां परीक्षण का एकमात्र हित संदर्भ गणना की जांच करता है, और dunit\Contrib\DUnitWizard\Source\DelphiExperts\DUnitProject\XPTestedUnitUtils.pas जहां XPObserver इकाई में केवल IXPFamily प्रकार घोषित किया जाता है।

इसलिए मुझे आश्चर्य है कि इस XPObserver इकाई का उपयोग करने का सबसे अच्छा अभ्यास क्या है।

उदाहरण के लिए:

(1) कैसे XPObserver इकाई का उपयोग करना एक पर्यवेक्षक पैटर्न है कि कुछ करने को लागू करने जैसे: डिजाइन सवाल?

(2) एक एमवीसी पैटर्न को लागू करने के लिए XPObserver का उपयोग कैसे करें?

या निम्न जैसे प्रश्नों कोडिंग:

(3) XPObserver के TXPSubjectssingle observer<->multiple subject संबंध को सक्षम करने की क्षमता प्रदान करने के लिए दावा किया है। हालांकि, FSubjects निजी घोषित किया गया है। कोई गेटर्स भी नहीं है। मुझे आश्चर्य है कि यह डिजाइन द्वारा है? (उदाहरण के लिए, लेखक ने TXPSubject.DeleteObserver में लिखा है। इस प्रकार मैं कोड को संशोधित करने के लिए आश्वस्त नहीं हूं क्योंकि मैं इसे और शायद अन्य भागों को पूरी तरह से समझ नहीं पा रहा हूं।) यदि हां, तो single observer<->multiple subject संबंध सक्षम करने के लिए TXPSubjects का उपयोग करने का क्या तरीका है?

आपके समय और टिप्पणियों के लिए बहुत बहुत धन्यवाद!

उत्तर

1

मुझे आपको उदाहरण दें कि XPObserver इकाई का उपयोग कैसे करें। पहले कई इंटरफेस एक डाटा मॉडल अनुकरण करने के लिए:

type 
    IColorChannel = interface(IXPSubject) 
    function GetValue: byte; 
    procedure RandomChange; 
    end; 

    IColorChannelObserver = interface(IXPObserver) 
    ['{E1586F8F-32FB-4F77-ACCE-502AFDAF0EC0}'] 
    procedure Changed(const AChannel: IColorChannel); 
    end; 

    IColor = interface(IXPSubject) 
    function GetValue: TColor; 
    end; 

    IColorObserver = interface(IXPObserver) 
    ['{0E5D2FEC-5585-447B-B242-B9B57FC782F2}'] 
    procedure Changed(const AColor: IColor); 
    end; 

IColorChannel सिर्फ एक byte मूल्य लपेटता है, यह मान देने के लिए तरीकों की है और बेतरतीब ढंग से इसे बदलने के लिए। यह IColorChannelObserver इंटरफ़ेस के कार्यान्वयनकर्ताओं द्वारा भी देखा जा सकता है जो स्वयं को इसके साथ पंजीकृत करते हैं।

IColor बस TColor मान लपेटता है, तो यह मूल्य वापस करने के लिए एक तरीका है। यह IColorObserver इंटरफ़ेस के कार्यान्वयनकर्ताओं द्वारा भी देखा जा सकता है जो स्वयं को इसके साथ पंजीकृत करते हैं।

एक वर्ग IColorChannel को लागू करने, इसके बारे में कुछ भी नहीं मुश्किल:

type 
    TColorChannel = class(TXPSubject, IColorChannel) 
    function GetValue: byte; 
    procedure RandomChange; 
    private 
    fValue: byte; 
    end; 

function TColorChannel.GetValue: byte; 
begin 
    Result := fValue; 
end; 

procedure TColorChannel.RandomChange; 
var 
    Value, Idx: integer; 
    Icco: IColorChannelObserver; 
begin 
    Value := Random(256); 
    if fValue <> Value then begin 
    fValue := Value; 
    for Idx := 0 to ObserverCount - 1 do begin 
     // Or use the Supports() function instead of QueryInterface() 
     if GetObserver(Idx).QueryInterface(IColorChannelObserver, Icco) = S_OK then 
     Icco.Changed(Self); 
    end; 
    end; 
end; 
अब

एक वर्ग आरजीबी के लिए IColor को लागू है, जो होते हैं और TColorChannel के तीन उदाहरणों का पालन करेंगे - यानी एक पर्यवेक्षक कई विषयों संबंध:

type 
    TRGBColor = class(TXPSubject, IColor, IColorChannelObserver) 
    function GetValue: TColor; 
    private 
    fRed: IColorChannel; 
    fGreen: IColorChannel; 
    fBlue: IColorChannel; 
    fValue: TColor; 
    function InternalUpdate: boolean; 
    public 
    constructor Create(ARed, AGreen, ABlue: IColorChannel); 

    procedure Changed(const AChannel: IColorChannel); 
    end; 

constructor TRGBColor.Create(ARed, AGreen, ABlue: IColorChannel); 
begin 
    Assert(ARed <> nil); 
    Assert(AGreen <> nil); 
    Assert(ABlue <> nil); 
    inherited Create; 
    fRed := ARed; 
    fRed.AddObserver(Self, fRed); 
    fGreen := AGreen; 
    fGreen.AddObserver(Self, fGreen); 
    fBlue := ABlue; 
    fBlue.AddObserver(Self, fBlue); 
    InternalUpdate; 
end; 

procedure TRGBColor.Changed(const AChannel: IColorChannel); 
var 
    Idx: integer; 
    Ico: IColorObserver; 
begin 
    if InternalUpdate then 
    for Idx := 0 to ObserverCount - 1 do begin 
     if GetObserver(Idx).QueryInterface(IColorObserver, Ico) = S_OK then 
     Ico.Changed(Self); 
    end; 
end; 

function TRGBColor.GetValue: TColor; 
begin 
    Result := fValue; 
end; 

function TRGBColor.InternalUpdate: boolean; 
var 
    Value: TColor; 
begin 
    Result := False; 
    Value := RGB(fRed.GetValue, fGreen.GetValue, fBlue.GetValue); 
    if fValue <> Value then begin 
    fValue := Value; 
    Result := True; 
    end; 
end; 

यदि तीन चैनल मूल्यों में से कोई भी परिवर्तन बदलता है तो रंग परिवर्तन लागू करेगा और बदले में इसके सभी पर्यवेक्षकों को सूचित करेगा।

अब इन कक्षाओं का उपयोग कर एक डेटा मॉड्यूल:

type 
    TDataModule1 = class(TDataModule) 
    procedure DataModuleCreate(Sender: TObject); 
    private 
    fRed: IColorChannel; 
    fGreen: IColorChannel; 
    fBlue: IColorChannel; 
    fColor: IColor; 
    public 
    property BlueChannel: IColorChannel read fBlue; 
    property GreenChannel: IColorChannel read fGreen; 
    property RedChannel: IColorChannel read fRed; 
    property Color: IColor read fColor; 
    end; 

procedure TDataModule1.DataModuleCreate(Sender: TObject); 
begin 
    Randomize; 

    fRed := TColorChannel.Create; 
    fGreen := TColorChannel.Create; 
    fBlue := TColorChannel.Create; 

    fColor := TRGBColor.Create(fRed, fGreen, fBlue); 
end; 

और अंत में एक रूप है जो डेटा मॉड्यूल का उपयोग करता है और केवल इंटरफेस के बारे में जानता है, को लागू करने कक्षाओं के बारे में कुछ भी नहीं:

type 
    TForm1 = class(TForm, IXPObserver, IColorChannelObserver, IColorObserver) 
    Button1: TButton; 
    Button2: TButton; 
    Button3: TButton; 
    StatusBar1: TStatusBar; 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    procedure ButtonClick(Sender: TObject); 
    public 
    procedure Changed(const AChannel: IColorChannel); overload; 
    procedure Changed(const AColor: IColor); overload; 
    procedure ReleaseSubject(const Subject: IXPSubject; 
     const Context: pointer); 
    private 
    fChannels: array[0..2] of IColorChannel; 
    fColor: IColor; 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    Idx: integer; 
begin 
    Button1.Caption := 'red'; 
    Button1.Tag := 0; 
    fChannels[0] := DataModule1.RedChannel; 

    Button2.Caption := 'green'; 
    Button2.Tag := 1; 
    fChannels[1] := DataModule1.GreenChannel; 

    Button3.Caption := 'blue'; 
    Button3.Tag := 2; 
    fChannels[2] := DataModule1.BlueChannel; 

    for Idx := 0 to 2 do 
    fChannels[Idx].AddObserver(Self, fChannels[Idx]); 

    fColor := DataModule1.Color; 
    fColor.AddObserver(Self, fColor); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
var 
    Idx: integer; 
begin 
    for Idx := Low(fChannels) to High(fChannels) do 
    fChannels[Idx].DeleteObserver(Self); 
    fColor.DeleteObserver(Self); 
end; 

procedure TForm1.ButtonClick(Sender: TObject); 
var 
    Button: TButton; 
begin 
    Button := Sender as TButton; 
    if (Button.Tag >= Low(fChannels)) and (Button.Tag <= High(fChannels)) then 
    fChannels[Button.Tag].RandomChange; 
end; 

procedure TForm1.Changed(const AChannel: IColorChannel); 
var 
    Idx: integer; 
begin 
    Assert(AChannel <> nil); 
    for Idx := Low(fChannels) to High(fChannels) do 
    if fChannels[Idx] = AChannel then begin 
     while StatusBar1.Panels.Count <= Idx do 
     StatusBar1.Panels.Add; 
     StatusBar1.Panels[Idx].Text := IntToStr(AChannel.GetValue); 
     break; 
    end; 
end; 

procedure TForm1.Changed(const AColor: IColor); 
begin 
    Assert(AColor <> nil); 
    Color := AColor.GetValue; 
end; 

procedure TForm1.ReleaseSubject(const Subject: IXPSubject; 
    const Context: pointer); 
var 
    Idx: integer; 
begin 
    // necessary if the objects implementing IXPSubject are not reference-counted 
    for Idx := Low(fChannels) to High(fChannels) do begin 
    if Subject = fChannels[Idx] then 
     fChannels[Idx] := nil; 
    end; 
    if Subject = fColor then 
    fColor := nil; 
end; 

प्रपत्र इंटरफेस लागू करता है लेकिन संदर्भ-गणना नहीं है। यह डेटा मॉड्यूल के चार गुणों में से प्रत्येक को देखने के लिए खुद को पंजीकृत करता है, जब भी कोई रंगीन चैनल बदलता है तो यह स्टेटस बार फलक में मान दिखाता है, जब रंग बदलता है तो यह अपने स्वयं के पृष्ठभूमि रंग को अपडेट करता है। रंग चैनलों को यादृच्छिक रूप से बदलने के लिए बटन हैं।

डेटा मॉड्यूल गुणों और डेटा को बदलने के अन्य साधनों के लिए दोनों अधिक पर्यवेक्षक हो सकते हैं।

फास्टएमएम 4 का उपयोग करके डेल्फी 5 और डेल्फी 200 दोनों में परीक्षण किया गया, कोई मेमोरी लीक नहीं है। फॉर्म में प्रत्येक AddObserver() के लिए DeleteObserver() की मिलान करने वाली कॉल नहीं होने पर लीक हो जाएगी।

संबंधित मुद्दे