在一个软件项目中,有一个这样的需求,软件首页列出待处理消息的个数,点击进入处理窗体,处理后,刷新首页的消息个数。从软件设计来说,消息处理类并不需要知道是哪里需要刷新,可以是首页,也可以是别的地方,或者同时多个地方。因此打算采用Observer模式。
先设计出类图:
TMsg是消息处理类,它通过LoadMsgs得到待处理消息,RegisteNewMsg方法注册观察者,UnregisterNewMsg移除观察者,现在消息处理后,能及时通知观察者进行更新了。
{-----------------------------------------------------------------------------
Unit Name: untMsgs
Author: bohe
Purpose:
History:
-----------------------------------------------------------------------------}
unit untMsgs;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls, MstProxyObj,
Forms, Dialogs, DBClient, variants, contnrs, StdCtrls;
type
TMsg = class(TObject)
private
FReadedMsgCount: Integer;
FNewMsgCount: Integer;
fSenderCode: string;
fcdsNewMsg: TClientDataSet;
fcdsReadedMsg: TClientDataSet;
function GetAllMsgCount: Integer; virtual;
procedure SetNewMsgCount(Value: Integer); virtual;
//function GetvAllMsgData: OleVariant;
function GetvNewMsgData: OleVariant;
function GetvReadedMsgData: OleVariant;
protected
fAllMsgCount: integer;
//fcdsMsg: TClientDataSet;
fEduMstObj: TMstEduProxyObj;
vMsgData: OLEVariant;
FNewMsgReaderList: TObjectList;
FReadedMsgReaderList: TObjectList;
//property cdsMsg: TClientDataSet read fcdsMsg;
procedure NotifyChange(ReaderList: TObjectList; Value: integer);
public
property vNewMsgData: OleVariant read GetvNewMsgData;
//property vAllMsgData: OleVariant read GetvAllMsgData;
property vReadedMsgData: OleVariant read GetvReadedMsgData;
constructor Create(sSenderCode: string; EduMstObj: TMstEduProxyObj);
destructor Destroy;
procedure LoadMsgs; virtual; abstract;
property AllMsgCount: Integer read GetAllMsgCount;
property NewMsgCount: Integer read FNewMsgCount; //write SetNewMsgCount;
property ReadedMsgCount: Integer read FReadedMsgCount;
procedure RegisterNewMsg(Reader: TCustomLabel);
procedure RegisterReadedMsg(Reader: TCustomLabel);
procedure UnregisterNewMsg(Reader: TCustomLabel);
function GetMsgCode(MsgID: integer): integer;
procedure SetMsgReaded(MsgID: integer);
end;
TBurMsg = class(TMsg)
public
procedure LoadMsgs; override;
end;
TSchMsg = class(TMsg)
public
procedure LoadMsgs; override;
end;
var
SchMsg: TSchMsg;
BurMsg: TBurMsg;
implementation
uses DB, untConst;
{
*************************************TMsg*********************************
}
constructor TMsg.Create(sSenderCode: string; EduMstObj: TMstEduProxyObj);
begin
fEduMstObj := EduMstObj;
fSenderCode := sSenderCode;
//fcdsMsg := TClientDataSet.Create(nil);
fcdsNewMsg := TClientDataSet.Create(nil);
fcdsReadedMsg := TClientDataSet.Create(nil);
vMsgData := null;
FNewMsgReaderList := TObjectList.Create;
FNewMsgReaderList.OwnsObjects := false;
FReadedMsgReaderList := TObjectList.Create;
FReadedMsgReaderList.OwnsObjects := false;
LoadMsgs;
end;
destructor TMsg.Destroy;
begin
//fcdsMsg.close;
//fcdsMsg.Free;
//fcdsNewMsg.Close;
fcdsNewMsg.Free;
fcdsReadedMsg.Free;
FNewMsgReaderList.Free;
FReadedMsgReaderList.Free;
end;
function TMsg.GetAllMsgCount: Integer;
begin
Result := fAllMsgCount; //;NewMsgCount + ReadedMsgCount;
end;
function TMsg.GetMsgCode(MsgID: integer): integer;
begin
Result := -1;
if fcdsNewMsg.Locate('id',MsgID,[]) then
Result := fcdsNewMsg.fieldByName('Msg_Code').AsInteger
else if fcdsReadedMsg.Locate('id',MsgID,[]) then
Result := fcdsReadedMsg.fieldByName('Msg_Code').AsInteger;
end;
function TMsg.GetvNewMsgData: OleVariant;
begin
Result := fcdsNewMsg.Data;
end;
function TMsg.GetvReadedMsgData: OleVariant;
begin
Result := fcdsReadedMsg.Data;
end;
procedure TMsg.NotifyChange(ReaderList: TObjectList; Value: integer);
var
i: integer;
begin
for i := 0 to ReaderList.Count -1 do
begin
if assigned(ReaderList[i]) then
(ReaderList[i] as TCustomLabel).Caption := IntToStr(Value);
end;
end;
procedure TMsg.RegisterNewMsg(Reader: TCustomLabel);
begin
Reader.Caption := IntToStr(FNewMsgCount);
FNewMsgReaderList.Add(Reader);
end;
procedure TMsg.RegisterReadedMsg(Reader: TCustomLabel);
begin
Reader.Caption := IntToStr(FReadedMsgCount);
FReadedMsgReaderList.Add(Reader);
end;
procedure TMsg.SetMsgReaded(MsgID: integer);
var
i: integer;
begin
if not fEduMstObj.ProxyObj.ReadAMsg(MsgID) then
raise Exception.Create('设置消息已读属性失败!');
if fcdsNewMsg.Locate('id',msgid,[]) then
begin
//将新消息里的记录插入到已读消息记录里
fcdsReadedMsg.Insert;
for i := 0 to fcdsNewMsg.FieldCount - 1 do
fcdsReadedMsg.Fields[i].Value := fcdsNewMsg.Fields[i].Value;
fcdsReadedMsg.Post;
fcdsNewMsg.Delete; //删除新生表里的记录
fNewMsgCount := fcdsNewMsg.RecordCount;
NotifyChange(FNewMsgReaderList,fNewMsgCount);
fReadedMsgCount := fcdsReadedMsg.RecordCount;
NotifyChange(FReadedMsgReaderList,fReadedMsgCount);
end;
end;
procedure TMsg.SetNewMsgCount(Value: Integer);
begin
end;
procedure TMsg.UnregisterNewMsg(Reader: TCustomLabel);
var
idx: integer;
begin
idx := FNewMsgReaderList.IndexOf(Reader);
if idx>=0 then
FNewMsgReaderList.Delete(idx);
end;
end.