首页 > 代码库 > 装饰者模式

装饰者模式

一.模式解说

以客户端透明的方式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案。装饰者模式用意是要保持对象接口,增强对象性能.

实际生活中经常发现装饰者模式.比如,你需要装裱挂画,你不想讲画和画框定死以便更换不同的画框.下图就是一个装裱挂画的装饰者模式.

技术分享

装饰者模式的使用时机:

1. 在不影响其他对象的情况下,动态透明的增加责任到一个对象.

2.希望责任和功能可以随时增加或取消.

3.当无法通过类继承来扩展功能时.

二.结构和用法

2.1 模式结构

 装饰者模式结构如下图:

技术分享

包含以下参与者:

1. 抽象部件(TComonent):定义一个接口可以动态的附加责任到其他对象.

2.具体部件(TConcreteComponent): 定义可以被附加责任的对象.

3.装饰者(TDecorator): 维护一个抽象部件对象的引用,并定义与抽象部件接口一致的接口,以便装饰抽象部件对象接口.

4.具体装饰者(TConcreteDecorator): 附加责任到抽象部件,完成具体的装饰.

2.2 代码模板(Delphi)

   

unit Decorator;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  Tcomponent = class(TObject)
  public
    procedure Operation; virtual; abstract;
  end;

  TConcreteComponent = class(Tcomponent)
  public
    procedure Operation; override;
  end;

  TDecorator = class(Tcomponent)
  private
    FComponent: TComponent;
  public
    constructor Create(Component: TComponent);
    procedure Operation;overload; override;
  end;

  TConcreteDecoratorA = class(TDecorator)
  private
    FAddedState: integer;
  public
    procedure Operation;override;
  end;

  TConcreteDecoratorB = class(TDecorator)
  public
    procedure AddedBehavior;
    procedure Operation;override;
  end;

implementation

{ TConcreteComponent }

procedure TConcreteComponent.Operation;
begin
  //被装饰者部件的操作代码
end;

{ TDecorator }

constructor TDecorator.Create(Component: TComponent);
begin
  FComponent := Component;
end;

procedure TDecorator.Operation;
begin
  if FComponent <> nil then
    FComponent.Operation;
end;

{ TConcreteDecoratorA }

procedure TConcreteDecoratorA.Operation;
begin
  //装饰部件操作代码
end;

{ TConcreteDecoratorB }

procedure TConcreteDecoratorB.AddedBehavior;
begin
  //装饰者新增操作的代码
end;

procedure TConcreteDecoratorB.Operation;
begin
  //装饰部件操作代码
  // 注意这里是装饰后已经扩展了对象的功能
  inherited Operation;
  AddedBehavior;
end;

end.

 2.3 问题讨论

技术分享

 三. 范例与实践

3.1 装饰者模式在图片观赏器中的应用

 技术分享

技术分享

技术分享

 

 

 部分示例代码:

unit PicDecorator;

interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, ComCtrls, Jpeg;

type

  TPicShow = class(TObject)
  public
    procedure Display(Owner: TForm; ImgFile: string); virtual; abstract;
  end;

  TPic = class(TPicShow)
  public
    procedure Display(Owner: TForm; ImgFile: string); override;
  end;

  TDecoratedPic = class(TPicShow)
  private
    FComponent: TPicShow;
  public
    constructor Create(PicShow: TPicShow);
    procedure Display(Owner: TForm; ImgFile: string); overload; override;
  end;

  TPicWithFrame = class(TDecoratedPic)
  private
    FAddedFrame: integer;
  public
    procedure Display(Owner: TForm; ImgFile: string); override;
    destructor Destroy; override;
  end;

  TPicWithMusic = class(TDecoratedPic)
  public
    destructor Destroy; override;
    procedure AddMusic;
    procedure Display(Owner: TForm; ImgFile: string); override;
  end;

implementation

{ TPic }

procedure TPic.Display(Owner: TForm; ImgFile: string);
var
  Img : TImage;
begin
  Img := TImage.Create(Owner);
  Img.Picture.LoadFromFile(ImgFile);
  Img.AutoSize := True;
  Img.Stretch := True;
  Owner.Width := Img.Width + 32;
  Owner.Height := Img.Height + 64;
  Owner.Caption := ImgFile;
  Img.Left := 11;
  Img.Top := 13;
  Img.Parent := Owner;
end;

{ TDecoratedPic }

constructor TDecoratedPic.Create(PicShow: TPicShow);
begin
  Self.FComponent := PicShow;
end;

procedure TDecoratedPic.Display(Owner: TForm; ImgFile: string);
begin
  if FComponent <> nil then
    FComponent.Display(Owner, ImgFile);
end;

{ TPicWithFrame }

destructor TPicWithFrame.Destroy;
begin
  if FComponent <> nil then FComponent.Free;
end;

procedure TPicWithFrame.Display(Owner: TForm; ImgFile: string);
var
  FrmOut: TBevel;
  FrmIn: TBevel;
begin
  inherited Display(Owner, ImgFile);
  FrmIn := Tbevel.Create(Owner);
  FrmIn.Parent := Owner;
  FrmIn.Width := Owner.Width - 30;
  FrmIn.Height := Owner.Height - 62;
  FrmIn.Left := 10;
  FrmIn.Top := 12;
  FrmIn.Shape := bsBox;
  FrmIn.Style := bsLowered;

  FrmOut := Tbevel.Create(Owner);
  FrmOut.Parent := Owner;
  FrmOut.Width := Owner.Width - 18;
  FrmOut.Height := Owner.Height - 48;
  FrmOut.Left := 4;
  FrmOut.Top := 6;
  FrmOut.Shape := bsBox;
  FrmOut.Style := bsRaised;
end;

{ TPicWithMusic }

procedure TPicWithMusic.AddMusic;
begin
  SndPlaySound(SONG.wav, SND_ASYNC or SND_NODEFAULT);
end;

destructor TPicWithMusic.Destroy;
begin
  if Self.FComponent <> nil then Self.FComponent.Free;
end;

procedure TPicWithMusic.Display(Owner: TForm; ImgFile: string);
begin
  inherited Display(Owner, ImgFile);
  AddMusic;
end;

end.

技术分享

技术分享

技术分享

技术分享

四.总结

技术分享

技术分享

 

装饰者模式