zoukankan      html  css  js  c++  java
  • 观察者模式

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

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

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

      因为主题是真正拥有数据的人,观察者是主题的依赖者,在数据变化时更新,这也比起让许多对象控制同一份数据来,可以得到更干净的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语言的事,可以忽略。。。

      

  • 相关阅读:
    深入理解计算机系统读书笔记之第二章信息的表示和处理
    深入理解计算机系统读书笔记之第一章:漫游
    算法三之归并排序
    算法二之子集和数问题
    算法一之N皇后问题
    刚刚注册写一写
    linux alias(命令别名)
    linux [CTRL]+c与[CTRL]+d
    linux终端类型
    linux 进程简介
  • 原文地址:https://www.cnblogs.com/hachun/p/3462685.html
Copyright © 2011-2022 走看看