长亭百川云 - 文章详情

装饰者模式

Delphi研习社

45

2024-07-13

鉴于当前这个号无法留言,所以我申请了新号,有兴趣的朋友可以去看看

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

引自【菜鸟教程】

优点:

装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能

缺点:

多层装饰比较复杂

UML 图解析

Component(抽象组件):具体构件与抽象装饰类的共同父类,声明具体构件中实现的业务方法,它的出现能够让客户端一致的透明的对待装饰前和装饰后的类

ConcreteComponent(具体组件):抽象构件的子类,实现具体的业务方法

Decorator(抽象装饰类):抽象构件的子类,内部维持一个抽象构件的引用,通过该引用调用具体构件的业务方法

ConcreteDecorator(具体装饰类):抽象装饰类的实现类,声明并实现各种装饰方法实现对具体构件的装饰

其实单纯的阅读上面的定义是很容易一头雾水。那么下面我尝试以游戏中的例子解释一下

实战案例

今天以瘟疫之源为例,老鼠的输出主要靠平 A,在没有装备和 Buff 的加持下相当于刮痧。这些加成对于原平 A 也只是叠加上去的加成,一层套一层。就像平 A 加上了减速效果、中毒效果,而这些效果又不影响

类图就不画了,直接上代码

代码实现

入口函数单元

program Decorate;  
  
{$APPTYPE CONSOLE}  
{$R *.res}  
  
{ 装饰设计模式 }  
uses  
  System.SysUtils,  
  DecorateUnit in 'DecorateUnit.pas';  
  
begin  
  try  
  
    // 装饰各种特效  
  
    var RetardDecorator := TRetardDecorator.Create(TNormalAttack.Create(120));  
  
    var PoisonDecorator := TPoisonDecorator.Create(RetardDecorator);  
    // 制造攻击  
    PoisonDecorator.MakeADAttack;  
  except  
    on E: Exception do  
      Writeln(E.ClassName, ': ', E.Message);  
  end;  
  
  Readln;  
end.  

代码实现单元

unit DecorateUnit;  
  
interface  
  
type  
  // 攻击接口  
  INormalAttack = interface  
    ['{D8FE89F6-8492-48E4-85BF-72C2940C2259}']  
    procedure MakeADAttack();  
  end;  
  
  // 普通攻击  
  TNormalAttack = class(TInterfacedObject, INormalAttack)  
  private  
    FAdAttack: Integer;  
  
  public  
    property AdAttack: Integer read FAdAttack write FAdAttack;  
    procedure MakeADAttack(); overload;  
  
    // 构造方法,用于初始化攻击值  
    constructor Create(AdAttack: Integer); overload;  
  end;  
  
  // 基础装饰器  
  TNormalAttackDecorator =  class abstract(TInterfacedObject, INormalAttack)  
  private  
    FNormalAttack: INormalAttack;  
  private  
    FSpecialEfficacy: string;  
  public  
    property NormalAttack: INormalAttack read FNormalAttack write FNormalAttack;  
    // 虚函数,不做函数实现  
    procedure MakeADAttack(); virtual; abstract;  
  
    constructor Create(NormalAttack: INormalAttack); overload;  
  end;  
  
  // 减速  
  TRetardDecorator = class(TNormalAttackDecorator)  
  public  
    procedure MakeADAttack(); override;  
  
    constructor Create(NormalAttack: INormalAttack); overload;  
  end;  
  // 中毒  
  
  TPoisonDecorator = class(TNormalAttackDecorator)  
  public  
    procedure MakeADAttack(); override;  
  
    constructor Create(NormalAttack: INormalAttack); overload;  
  end;  
  
  
implementation  
  
{ TNormalAttack }  
uses  
  System.SysUtils;  
  
constructor TNormalAttack.Create(AdAttack: Integer);  
begin  
  
  Self.AdAttack := AdAttack;  
end;  
  
procedure TNormalAttack.MakeADAttack;  
begin  
  Writeln('初始攻击值为:' + Self.AdAttack.ToString);  
end;  
  
{ TNormalAttackDecorator }  
  
constructor TNormalAttackDecorator.Create(NormalAttack: INormalAttack);  
begin  
  
  Self.NormalAttack := NormalAttack;  
  
  
end;  
  
{ TRetardDecorator }  
  
constructor TRetardDecorator.Create(NormalAttack: INormalAttack);  
begin  
  inherited Create(NormalAttack);  
  self.FSpecialEfficacy := '减速';  
end;  
  
procedure TRetardDecorator.MakeADAttack;  
begin  
  Self.NormalAttack.MakeADAttack();  
  Writeln('增加了' + self.FSpecialEfficacy + 'Buff');  
  
end;  
  
{ TPoisonDecorator }  
  
constructor TPoisonDecorator.Create(NormalAttack: INormalAttack);  
begin  
  inherited Create(NormalAttack);  
  self.FSpecialEfficacy := '中毒';  
end;  
  
procedure TPoisonDecorator.MakeADAttack;  
begin  
  
  Self.NormalAttack.MakeADAttack();  
  
  Writeln('增加了' + self.FSpecialEfficacy + 'Buff');  
end;  
  
end.

执行结果

小结

本来设计模式的学习我都是以 Java 先行实现一边,然后翻译成对应的 Delphi 代码。毕竟代码不熟悉,这里面有个小插曲,在这里特别说一下

abstract 关键字

我是在读系统代码的时候发现类的声明部分是可以带有这个关键字的,基本格式

type  
  
    TDemo=class abstract  
  
    end;  

但是我今天遇到的问题是当 TNormalAttackDecorator 类时按照上面的格式直接报错,经群又指点修正之后问题解决了

type  
  
    TNormalAttackDecorator =  class abstract(TInterfacedObject, INormalAttack)  
  
    end;  

override 和 overload

代码中我全部都用 overload 然后死活编译不过,还是群里的朋友 简单 指点的。特别感谢,顺便将两者的区别整理如下

  • override 关键字来说明函数覆盖的。被覆盖的函数必须是虚 (virtual) 的,或者是动态 (dynamic) 的

  • overload 表示是重载方法;用于一个类中有许多同名的方法带着不同的参数表的情形

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2