《GOF设计模式》—代理(PROXY)—Delphi源码示例:文档编辑器(使用doesNotUnderstand的Proxy)

示例:使用doesNotUnderstandProxy

说明:

Smalltalk中,你可以定义超类为nil的类,同时定义doesNotUnderstand方法处理消息,这样构建一些通用的代理。

在以下程序中我们假设代理有一个realSubject方法,该方法返回它的实体。在ImageProxy中,该方法将检查是否已创建了Image,并在必要的时候创建它,最后返回Image。它使用perform来执行被保留在实体中的那些消息。

doesNotUnderstand的参数是Message的一个实例,它表示代理不能理解的消息。所以,代理在转发消息给实体之前,首先确定实体的存在性,并由此对所有的消息做出响应。

doesNotUnderstand的一个优点是它可以执行任意的处理过程。例如,我们可以用这样的方式生成一个protection proxy,即指定一个可以接受的消息的集合legalMessages,这个方法在向实体转发一个消息之前,检查它的合法性。如果不是合法的,那么提示error

 

代码:

unit uDocument1;

 

interface

 

uses

    Windows,Messages,Classes,Graphics,Contnrs;

 

const

    CM_ImageError = WM_USER + 1;

    CM_ImageDraw = WM_USER + 2;

    CM_ImageExtent = WM_USER + 3;

 

    legalMessages: array[0..1] of integer = (CM_ImageDraw,CM_ImageExtent);

 

type

    TImage1 = class(TObject)

    private

        FFileName: string;

        FBitmap: TBitmap;

    public

        constructor Create(const AImageFile: string);

        destructor Destroy; override;

        //---

        procedure Draw(var AMessage: TMessage);

        procedure GetExtent(var AMessage: TMessage);

        //---

        procedure Perform(var AMessage: TMessage);

    end;

 

    TImageProxy = class

    private

        FImage: TImage1;

        FExtent: TPoint;

        FFileName: string;

        function RealSubject: TImage1;

    protected

        procedure Error(const AMsg: string);

        procedure DoesNotUnderstand(var AMessage: TMessage);

    public

        constructor Create(const AImageFile: string);

        destructor Destroy; override;

        //---

        procedure Dispatch(var Message); override;

    end;

 

    TTextDocument = class

    private

        FCanvas: TCanvas;

        FGraphics: TObjectList;

    public

        constructor Create(const ACanvas: TCanvas);

        destructor Destroy; override;

        //---

        procedure Insert(aGraphic: TObject);

        procedure Draw;

        //---

        property Canvas: TCanvas read FCanvas;

    end;

 

implementation

 

constructor TImage1.Create(const AImageFile: string);

begin

    inherited Create;

    //---

    FFileName := AImageFile;

    //---

    FBitmap := TBitmap.Create;

    FBitmap.LoadFromFile(FFileName);

end;

 

destructor TImage1.Destroy;

begin

    if assigned(FBitmap) then

        FBitmap.Free;

    //---

    inherited;

end;

 

procedure TImage1.Draw(var AMessage: TMessage);

begin

    with AMessage do

    begin

        TTextDocument(WParam).Canvas.Draw(LParamLo,LParamHi,FBitmap);

        Result := 1;

    end;

end;

 

procedure TImage1.GetExtent(var AMessage: TMessage);

begin

    with AMessage do

    begin

        LParamLo := FBitmap.Width;

        LParamHi := FBitmap.Height;

        Result := 1;

    end;

end;

 

procedure TImage1.Perform(var AMessage: TMessage);

begin

    case AMessage.Msg of

        CM_ImageDraw: Draw(AMessage);

        CM_ImageExtent: GetExtent(AMessage);

    end;

end;

 

function TImageProxy.RealSubject: TImage1;

begin

    if FImage = nil then

        FImage := TImage1.Create(FFileName);

    result := FImage;

end;

 

constructor TImageProxy.Create(const AImageFile: string);

begin

    inherited Create;

    //---

    FFileName := AImageFile;

    FExtent := Point(0,0);

    FImage := nil;

end;

 

destructor TImageProxy.Destroy;

begin

    if Assigned(FImage) then

        FImage.Free;

    //---

    inherited

end;

 

constructor TTextDocument.Create(const ACanvas: TCanvas);

begin

    FGraphics := TObjectList.Create;

    FCanvas := ACanvas;

end;

 

destructor TTextDocument.Destroy;

begin

    FGraphics.Free;

    //---

    inherited;

end;

 

procedure TTextDocument.Draw;

var

    at: TPoint;

    i: integer;

    //---

    procedure _Draw(AGraphic: TObject);

    var

        AMessage: TMessage;

    begin

        with AMessage do

        begin

            Msg := CM_ImageDraw;

            WParam := Integer(Self);

            LParamLo := at.X;

            LParamHi := at.Y;

        end;

        AGraphic.Dispatch(AMessage);

    end;

    //---

    function _GetExtent(AGraphic: TObject): TPoint;

    var

        AMessage: TMessage;

    begin

        with AMessage do

        begin

            Msg := CM_ImageExtent;

            WParam := Integer(Self);

        end;

        AGraphic.Dispatch(AMessage);

        //---

        Result := Point(AMessage.LParamLo,AMessage.LParamHi);

    end;

begin

    at := Point(0,0);

    //---

    with FGraphics do

    begin

        for i := 0 to Count - 1 do

        begin

            _Draw(Items[i]);

            at.Y := at.Y + _GetExtent(Items[i]).Y;

        end;

    end;

end;

 

procedure TTextDocument.Insert(aGraphic: TObject);

begin

    FGraphics.Add(aGraphic);

end;

 

procedure TImageProxy.Dispatch(var Message);

begin

    DoesNotUnderstand(TMessage(Message));

    if TMessage(Message).Result = 0 then

        inherited;

end;

 

procedure TImageProxy.DoesNotUnderstand(var AMessage: TMessage);

    //---

    function _InlegalMessages: boolean;

    var

        i: integer;

    begin

        for i := low(legalMessages) to high(legalMessages) do

        begin

            if legalMessages[i] = AMessage.Msg then

            begin

                Result := true;

                exit;

            end;

        end;

        //---

        Result := false;

    end;

begin

    if _InlegalMessages then

        self.RealSubject.Perform(AMessage)

    else if AMessage.Msg = CM_ImageError then

    begin

        //…………

        AMessage.Result := 1;

    end

    else

        self.Error('Illegal operator');

end;

 

procedure TImageProxy.Error(const AMsg: string);

var

    AMessage: TMessage;

begin

    with AMessage do

    begin

        Msg := CM_ImageError;

        WParam := Integer(AMsg);

    end;

    self.Dispatch(AMessage);

end;

 

end.

 

procedure TForm1.Button1Click(Sender: TObject);

var

    ADocument: TTextDocument;

begin

    ADocument := TTextDocument.Create(self.Canvas);

    try

        ADocument.Insert(TImageProxy.Create('D:/temp/test.bmp'));

        ADocument.Insert(TImageProxy.Create('D:/temp/test1.bmp'));

        ADocument.Draw;

    finally

        ADocument.Free;

    end;

end;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值