观察者模式 其实就相当于 出版者+订阅者 的关系,当有新闻时,订阅者就会得到来自出版者那边的报纸;当然,若不想订阅报纸,取消订阅即可,之后出版者也就不会再发报纸给你;反之,若想订阅报纸,注册为订阅者即可。

  观察者模式的定义:观察者模式定义了对象之间的一对多依赖关系【主题(出版者)与观察者(订阅者)】,观察者依赖于此主题,只要主题状态一有变化,观察者就会被通知,根据通知的风格,观察者可能因此新值而更新。下面稍微解析一下定义:

  主题与观察者之间的一对多关系:利用观察者模式,主题是有状态的对象,并且可以控制这些状态,也就是说,有“一个”具有状态的主题;另一方面,观察者使用这些状态,虽然这些状态并不属于它们。有许多观察者依赖主题来告诉他们状态何时改变了,因此得到更新,这就产生了一对多的关系。

  因为主题是真正拥有数据的人,观察者是主题的依赖者,在数据变化时更新,这也比起让许多对象控制同一份数据来,可以得到更干净的OO设计。

  涉及到的OO设计原则:为了交互对象之间的松耦合而努力。

  下面看看观察者模式是如何采用上面的设计原则:

  松耦合即两个对象之间仍然可以交互,但是不太清楚彼此的细节。关于观察者的一切,主题只在乎观察者实现了某个接口,并不需要知道观察者的具体类是谁,做了什么或其他细节。当有新类型的观察者出现时,主题的代码不需要修改,要做的就是在新类中实现观察者接口,然后注册为观察者即可。改变主题或观察者其中一方,并不会影响另一方,因为两者是松耦合的,只要他们之间的接口仍然被遵守,我们就可以自由地改变他们。

delphi代码示例:

主题代码:

unit unt_Obserable;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  Windows, ActiveX, Classes, ComObj, Project2_TLB, StdVcl;

type
  TObserable = class(TTypedComObject, IObserable)
  protected
    function Notice: HResult; stdcall;
    function Resister(const Value: IObserver): HResult; stdcall;
    function Initial: HResult; stdcall;
    function Set_Subject(const Value: WideString): HResult; stdcall;
    {Declare IObserable methods here}

  private
    bChange: Boolean;
    iIndex: Integer;
    pArray: array of IObserver;
    m_Subject: string;
  end;

implementation

uses ComServ;

function TObserable.Initial: HResult;
begin
  iIndex := 0;
end;

function TObserable.Resister(const Value: IObserver): HResult;
begin
  Inc(iIndex);
  SetLength(pArray, iIndex);
  pArray[iIndex - 1] := Value;
end;

{$J+}
function TObserable.Set_Subject(const Value: WideString): HResult;
const
  sSubject: string = '';
begin
  if sSubject = Value then
  begin
    bChange := False;
  end
  else
  begin
    m_Subject := Value;
    sSubject := Value;
    bChange := True;
  end;
end;
{$J-}

function TObserable.Notice: HResult;
var
  i: Integer;
begin
  if not bChange then Exit;
  for i := 0 to Length(pArray) - 1 do
  begin
    pArray[i].Update(m_Subject);
  end; 
end;

initialization
  TTypedComObjectFactory.Create(ComServer, TObserable, Class_Obserable,
                   ciMultiInstance, tmApartment);
end.

观察者代码:

unit unt_Observer;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  Windows, ActiveX, Classes, ComObj, Project2_TLB, StdVcl;

type
  TObserver = class(TTypedComObject, IObserver)
  protected
    procedure Update(const Value: WideString); safecall;
    procedure Initial(const Value: WideString); safecall;
    procedure Set_Observable(const Value: IObserable); safecall;

  private
    pObserable: IObserable;
    sMsg: string;

  public
    function GetIDsOfNames(const IID: TGUID; Names: Pointer;
                 NameCount: Integer; LocaleID: Integer;                                                                                                                                                         DispIDs: Pointer): HRESULT;stdcall;

    function GetTypeInfoCount(out Count: Integer): HRESULT; stdcall;

    function GetTypeInfo(Index: Integer; LocaleID: Integer;out TypeInfo): HRESULT; stdcall;

    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
            Flags: Word; var Params; VarResult: Pointer; ExcepInfo: Pointer;
            ArgErr: Pointer): HRESULT; stdcall;

    {Declare IObserer methods here}
  end;

implementation

uses
  ComServ, unt_Comm;

{ TObserable }

function TObserver.GetIDsOfNames(const IID: TGUID; Names: Pointer;
                   NameCount, LocaleID: Integer; DispIDs: Pointer): HRESULT;
begin

end;

function TObserver.GetTypeInfo(Index, LocaleID: Integer;
                 out TypeInfo): HRESULT;
begin

end;

function TObserver.GetTypeInfoCount(out Count: Integer): HRESULT;
begin

end;

procedure TObserver.Initial(const Value: WideString);
begin
  sMsg := Value;
end;

function TObserver.Invoke(DispID: Integer; const IID: TGUID;
              LocaleID: Integer; Flags: Word; var Params;                                                                                                                                                                              VarResult, ExcepInfo,ArgErr: Pointer): HRESULT;

begin

end;

procedure TObserver.Set_Observable(const Value: IObserable);
begin
  pObserable := Value;
  pObserable.Resister(Self);
end;

procedure TObserver.Update(const Value: WideString);
begin
  InfoDlg(sMsg + '值变成【' + Value + '】了...');
end;

initialization
  TTypedComObjectFactory.Create(ComServer, TObserver, CLASS_TObserver,
                   ciMultiInstance, tmApartment);
end.

 测试代码:

procedure TForm1.btn1Click(Sender: TObject);
var
  pObserable: IObserable;
  pOberver: IObserver;
begin
  pObserable := CoObserable.Create;
  try
    pObserable.Initial;

    pOberver := CoTObserver.Create;
    pOberver.Initial('我是第一个观察者.');
    pOberver.Set_Observable(pObserable);

    pOberver := CoTObserver.Create;
    pOberver.Initial('我是第二个观察者.');
    pOberver.Set_Observable(pObserable);

    pOberver := CoTObserver.Create;
    pOberver.Initial('我是第三个观察者.');
    pOberver.Set_Observable(pObserable);

    pObserable.Set_Subject(edt1.Text);
    pObserable.Notice;
  finally
    pObserable := nil;
    pOberver := nil;
  end;
end;

  观察者模式不是很难理解,所以代码的注释几乎没有,上面有一些方法只是定义了一下,而没有具体实现,那是Delphi语言的事,可以忽略。。。

  

posted on 2013-12-07 12:54  花爱春  阅读(396)  评论(0编辑  收藏  举报