《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:封装复杂的更新语义
来源:互联网 发布:编程四大魔道天才 编辑:程序博客网 时间:2024/04/28 17:28
示例:封装复杂的更新语义
说明:
当目标和观察者间的依赖关系特别复杂时,可能需要一个维护这些关系的对象。我们称这样的对象为更改管理器(ChangeManager)。它的目的是尽量减少观察者反映其目标的状态变化所需的工作量。例如,如果一个操作涉及到对几个相互依赖的目标进行改动,就必须保证仅在所有的目标都已更改完毕后,才一次性地通知它们的观察者,而不是每个目标都通知观察者。
ChangeManager是一个中介者模式(Mediator)的实例。通常只有一个ChangeManager,并且它是全局可见的。这里单件模式(Singleton)可能有用。
代码:
unit uObserver5;
interface
uses
SysUtils, Classes,Dialogs;
type
TSubject = class;
TChangeManager = class;
TObserver = class
public
destructor Destroy; override;
//---
procedure Update(ASubject: TSubject); virtual; abstract;
end;
TConcreteObserver = class(TObserver)
private
FState: Integer;
public
procedure Update(ASubject: TSubject); override;
end;
TSubject = class
private
FChman: TChangeManager;
FNotifyEnabled: Boolean;
procedure SetNotifyEnabled(const Value: Boolean);
public
constructor Create;
destructor Destroy; override;
//---
procedure Attach(AObserver: TObserver);
procedure Detach(AObserver: TObserver);
procedure Notify();
//---
property NotifyEnabled: Boolean read FNotifyEnabled write SetNotifyEnabled;
end;
TConcreteSubject = class(TSubject)
private
FState: Integer;
procedure SetState(const Value: Integer);
public
property State: Integer read FState write SetState;
end;
RMapInfo = record
case Integer of
0: (
Item: Pointer;
Items: TList;
);
1: (
Subject: TSubject;
Observers: TList;
);
2: (
Observer: TObserver;
Subjects: TList;
);
end;
PMapInfo = ^RMapInfo;
TMapList = class(TList)
private
function GetItems(Index: Integer): PMapInfo;
protected
procedure Notify(Ptr: Pointer; Action: TListNotification); override;
public
procedure Add(AItem1, AItem2: Pointer);
function IndexOf(AItem: Pointer): Integer;
procedure Delete(AItem1, AItem2: Pointer);
//---
property Items[Index: Integer]: PMapInfo read GetItems;default;
end;
TChangeManager = class
private
FSubjects: TMapList;
FObservers: TMapList;
public
constructor Create;
destructor Destroy; override;
//---
class function Instance: TChangeManager;
//---
procedure Register1(ASubject: TSubject; AObserver: TObserver);
procedure UnRegister1(ASubject: TSubject; AObserver: TObserver);
procedure Notify; virtual; abstract;
end;
TSimpleChangeManager = class(TChangeManager)
public
procedure Notify; override;
end;
TDAGChangeManager = class(TChangeManager)
public
procedure Notify; override;
end;
procedure Test;
implementation
var
FChangeManager: TChangeManager;
procedure Test;
//---
procedure _Test1;
var
ASubject: TConcreteSubject;
AObserver: TObserver;
begin
ASubject := TConcreteSubject.Create;
AObserver := TConcreteObserver.Create;
try
ASubject.Attach(AObserver);
ASubject.State := 123;
finally
AObserver.Free;
ASubject.Free;
end;
end;
//---
procedure _Test2;
var
ASubject: TConcreteSubject;
AObserver1,AObserver2: TObserver;
begin
ASubject := TConcreteSubject.Create;
AObserver1 := TConcreteObserver.Create;
AObserver2 := TConcreteObserver.Create;
try
ASubject.Attach(AObserver1);
ASubject.Attach(AObserver2);
//---
ASubject.State := 123;
finally
AObserver1.Free;
AObserver2.Free;
ASubject.Free;
end;
end;
//---
procedure _Test3;
var
ASubject1,ASubject2: TConcreteSubject;
AObserver: TObserver;
begin
ASubject1 := TConcreteSubject.Create;
ASubject2 := TConcreteSubject.Create;
AObserver := TConcreteObserver.Create;
try
ASubject1.Attach(AObserver);
ASubject2.Attach(AObserver);
//---
ASubject1.State := 1;
ASubject2.State := 2;
finally
AObserver.Free;
ASubject1.Free;
ASubject2.Free;
end;
end;
//---
procedure _Test4;
var
ASubject1,ASubject2: TConcreteSubject;
AObserver1,AObserver2: TObserver;
begin
ASubject1 := TConcreteSubject.Create;
ASubject2 := TConcreteSubject.Create;
AObserver1 := TConcreteObserver.Create;
AObserver2 := TConcreteObserver.Create;
try
ASubject1.Attach(AObserver1);
ASubject1.Attach(AObserver2);
ASubject2.Attach(AObserver1);
ASubject2.Attach(AObserver2);
//---
ASubject1.State := 1;
ASubject2.State := 2;
finally
AObserver1.Free;
AObserver2.Free;
ASubject1.Free;
ASubject2.Free;
end;
end;
begin
_Test4;
end;
constructor TSubject.Create;
begin
inherited;
//---
FChman := TChangeManager.Instance;
end;
destructor TSubject.Destroy;
begin
FChman.UnRegister1(self, nil);
//---
inherited;
end;
procedure TSubject.Attach(AObserver: TObserver);
begin
FChman.Register1(Self, AObserver);
end;
procedure TSubject.Detach(AObserver: TObserver);
begin
FChman.Unregister1(Self, AObserver);
end;
procedure TSubject.Notify();
begin
FChman.Notify;
end;
procedure TSubject.SetNotifyEnabled(const Value: Boolean);
begin
FNotifyEnabled := Value;
if FNotifyEnabled then
begin
Self.Notify;
FNotifyEnabled := False;
end;
end;
procedure TConcreteObserver.Update(ASubject: TSubject);
begin
FState := FState + TConcreteSubject(ASubject).State;
ShowMessage(IntToStr(FState));
end;
constructor TChangeManager.Create;
begin
if FChangeManager = nil then
begin
FChangeManager := Self;
FSubjects := TMapList.Create;
FObservers := TMapList.Create;
end
else
raise Exception.Create('Error');
end;
destructor TChangeManager.Destroy;
begin
FSubjects.Free;
FObservers.Free;
FChangeManager := nil;
//---
inherited;
end;
class function TChangeManager.Instance: TChangeManager;
begin
if FChangeManager = nil then
FChangeManager := TSimpleChangeManager.Create;
//FChangeManager := TDAGChangeManager.Create;
//---
Result := FChangeManager;
end;
procedure TChangeManager.Register1(ASubject: TSubject;
AObserver: TObserver);
begin
FSubjects.Add(ASubject, AObserver);
FObservers.Add(AObserver, ASubject);
end;
procedure TChangeManager.UnRegister1(ASubject: TSubject;
AObserver: TObserver);
begin
FSubjects.Delete(ASubject, AObserver);
FObservers.Delete(AObserver, ASubject);
end;
procedure TSimpleChangeManager.Notify;
var
i, j: Integer;
ASubject: TSubject;
AObserver: TObserver;
begin
for i := 0 to FSubjects.Count - 1 do
begin
with FSubjects[i]^ do
begin
ASubject := Subject;
if ASubject.NotifyEnabled then
begin
for j := 0 to Observers.Count - 1 do
begin
AObserver := Observers[j];
AObserver.Update(ASubject);
end;
end;
end;
end;
end;
procedure TMapList.Add(AItem1, AItem2: Pointer);
//---
procedure _Add; overload;
var
pData: PMapInfo;
begin
New(pData);
pData.Items := TList.Create;
//---
pData.Item := AItem1;
pData.Items.Add(AItem2);
//---
inherited Add(pData);
end;
//---
procedure _Add(AList: TList); overload;
var
AIndex: Integer;
begin
AIndex := AList.IndexOf(AItem2);
if AIndex < 0 then
AList.Add(AItem2);
end;
var
AIndex: Integer;
begin
AIndex := Self.IndexOf(AItem1);
if AIndex < 0 then
_Add
else
_Add(Self.Items[AIndex].Items);
end;
procedure TMapList.Delete(AItem1, AItem2: Pointer);
//---
procedure _DelItem(AList: TList);
var
AIndex: Integer;
begin
with AList do
begin
AIndex := IndexOf(AItem2);
if AIndex >= 0 then
Delete(AIndex);
end;
end;
//---
procedure _Delete1;
var
i: Integer;
begin
for i := self.Count - 1 downto 0 do
begin
with Self.Items[i]^ do
begin
_DelItem(Items);
if Items.Count = 0 then
inherited Delete(i);
end;
end;
end;
//---
procedure _Delete2;
var
AIndex: Integer;
begin
AIndex := self.IndexOf(AItem1);
if AIndex >= 0 then
inherited Delete(AIndex);
end;
//---
procedure _Delete3;
var
AIndex: Integer;
begin
AIndex := self.IndexOf(AItem1);
if AIndex >= 0 then
begin
with Self.Items[AIndex]^ do
begin
_DelItem(Items);
if Items.Count = 0 then
inherited Delete(AIndex);
end;
end;
end;
begin
if (AItem1 = nil) and (AItem2 = nil) then
Exit;
//---
if (AItem1 = nil) then
_Delete1
else if (AItem2 = nil) then
_Delete2
else
_Delete3;
end;
function TMapList.GetItems(Index: Integer): PMapInfo;
begin
Result := inherited Items[Index];
end;
function TMapList.IndexOf(AItem: Pointer): Integer;
var
i: Integer;
begin
for i := 0 to self.Count - 1 do
begin
if (Self.Items[i].Item = AItem) then
begin
Result := i;
Exit;
end;
end;
//---
Result := -1;
end;
procedure TMapList.Notify(Ptr: Pointer; Action: TListNotification);
var
pData: PMapInfo;
begin
if Action = lnDeleted then
begin
pData := Ptr;
pData.Items.Free;
Dispose(pData);
end;
//---
inherited;
end;
destructor TObserver.Destroy;
begin
TChangeManager.Instance.UnRegister1(nil, self);
//---
inherited;
end;
procedure TDAGChangeManager.Notify;
var
i: Integer;
ASubject: TSubject;
AObserver: TObserver;
begin
for i := 0 to FObservers.Count - 1 do
begin
with FObservers[i]^ do
begin
AObserver := Observer;
if Subjects.Count > 0 then
begin
ASubject := Subjects.Last;
if ASubject.NotifyEnabled then
AObserver.Update(ASubject);
end;
end;
end;
end;
procedure TConcreteSubject.SetState(const Value: Integer);
begin
FState := Value;
Self.NotifyEnabled := True;
end;
initialization
FChangeManager := nil;
finalization
if FChangeManager <> nil then
FChangeManager.Free;
end.
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:封装复杂的更新语义
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:观察者接口
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:图形用户界面工具箱
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:推模型(push model)
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:拉模型(pull model)
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:时钟
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:图形用户界面工具箱
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:显式地指定感兴趣的改变
- 《GOF设计模式》—迭代器 (ITERATOR)—Delphi源码示例:内部迭代器(封装不同类型的迭代)
- 《GOF设计模式》—桥接(BRIDGE)—Delphi源码示例:可移植的用户界面
- 《GOF设计模式》—桥接(BRIDGE)—Delphi源码示例:可移植的用户界面
- 《GOF设计模式》—中介者 (MEDIATOR)—Delphi源码示例:Colleague—Mediator通信(使用观察者模式)
- 《GOF设计模式》—代理(PROXY)—Delphi源码示例:更新前拷贝机制(copy-on-write)
- 《GOF设计模式》—创建型模式—Delphi源码示例:未基于模式的迷宫
- 《GOF设计模式》—组合(COMPOSITE)—Delphi源码示例:声明管理子部件的操作(安全性设计)
- 《GOF设计模式》—组合(COMPOSITE)—Delphi源码示例:声明管理子部件的操作(透明性设计)
- 《GOF设计模式》—外观(FACADE)—Delphi源码示例:基于外观模式的编译子系统
- 《GOF设计模式》—备忘录(MEMENTO)—Delphi源码示例:一个反映备忘录模式的迭代接口
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:显式地指定感兴趣的改变
- excle数据库blob处理(转)
- dev xGridControl Cell添加图片
- 两个小时学会DirectDraw编程
- 曾经使用过的文件下载方法
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:封装复杂的更新语义
- 安装cmake(解决can't find build-essential,解决windows如何远程控制ubuntu)
- DEV杂集
- installanywhere打包j2ee(java、tomcat、mysql)的具体步骤 转载
- 《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:时钟
- 转载eclipse web service开发IDE使用过程
- 练习2-8:创建一个vector,并用一个for循环语句向它输入25个浮点数,显示vector的结果。
- operator new()、placement new()与new关键字
- XGrid显示设置行的字体颜色