मुझे आपको उदाहरण दें कि 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()
की मिलान करने वाली कॉल नहीं होने पर लीक हो जाएगी।