长亭百川云 - 文章详情

享元模式

Delphi研习社

40

2024-07-13

享元模式(Flyweight Pattern)是一种结构型设计模式,首先说享元的含义,享元即有共享单元的意思。它主要解决的问题是创建大量相似对象时的内存开销问题。该模式通过共享具有相同状态的对象来减少内存使用量

当一个系统中存在大量重复对象,若这些重复的对象是不可变对象,就能利用享元模式将对象设计成享元,在内存中只保留一份实例,供引用。这就减少内存中对象的数量,最终节省内存。

"不可变对象":一旦通过构造器初始化完成后,其状态(对象的成员变量或属性)就不会再被修改。所以,不可变对象不能暴露任何 set()等修改内部状态的方法。之所以要求享元是不可变对象,是因为它会被多处代码共享使用,避免一处代码对享元进行了修改,影响到其他使用它的代码。

共享对象的状态分为 内部状态 与 外部状态 ,内部状态在各个对象间共享,而外部状态由客户端传入,这一点一定要牢记

优点

大大减少对象的创建,降低系统的内存,使效率提高。

缺点

提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

类图解析

由上图可以看出由 3 部分组成

  • Flyweight:享元接口,定义所有对象共享的操作

  • ConcreteFlyweight:具体的要被共享的对象,其一般是一个不可变类,内部只保存需要共享的内部状态,它可能不止一个。

  • FlyweightFactory:负责给客户端提供共享对象

代码实例

其实在示例上我一直想靠游戏来进行说明,但是很抱歉并没有那一款游戏符合。而网络上更多的是以五子棋为例,那就以五子棋为例吧。其实这是因为这里需要大量的棋子对象,它们除了颜色有黑白之分,摆放的位置不同其他都一样,非常适合使用享元模式

客户端代码

program Flyweight;  
  
{$APPTYPE CONSOLE}  
  
{$R *.res}  
  
uses  
  System.SysUtils,  
  System.TypInfo,  
  UnitFlyweight in 'UnitFlyweight.pas';  
  
var  
  r1: IChess;  
  
begin  
  try  
  
    var ChessFactory := TChessFactory.Create();  
    //下黑子  
    var BackChess1 := ChessFactory.GetChess(Tcolor.BLACK);  
    BackChess1.Draw(1, 2);  
     //下白子  
    var WhiteChess1 := ChessFactory.GetChess(Tcolor.WHITE);  
    WhiteChess1.Draw(2, 2);  
    //下黑子  
    var BackChess2 := ChessFactory.GetChess(Tcolor.BLACK);  
    BackChess2.Draw(1, 3);  
    var BackChess3 := ChessFactory.GetChess(Tcolor.BLACK);  
    BackChess3.Draw(1, 3);  
    //打印一下内存地址  
    writeln(Integer(WhiteChess1),',',Integer(BackChess1), ',', Integer(BackChess2), ',', Integer(BackChess3));  
  except  
    on E: Exception do  
      Writeln(E.ClassName, ': ', E.Message);  
  end;  
  
  Readln;  
end.  

核心代码

unit UnitFlyweight;  
  
interface  
  
uses  
  System.Generics.Collections;  
  
type  
    //定义一个枚举类型  
  TColor = (BLACK, WHITE);  
  
type  
    //定义一个共享对象通用的接口  
  IChess = interface  
    //绘制棋子  
    procedure Draw(x, y: Integer);  
  end;  
  
type  
    //黑棋类  
  TBlackChess = class(TInterfacedObject, IChess)  
  private  
   //内部状态,共享  
    FColor: TColor;  
    const  
      SHARP: string = '圆形';  
  public  
    //重写接口中的函数  
    procedure Draw(x, y: Integer); overload;  
    //重写构造  
    constructor Create(); overload;  
  end;  
  
type  
    //白棋类  
  TWhiteChess = class(TInterfacedObject, IChess)  
  private  
   //内部状态,共享  
    FColor: TColor;  
    const  
      SHARP: string = '圆形';  
  public  
    //重写接口中的函数  
    procedure Draw(x, y: Integer); overload;  
    //重写构造  
    constructor Create(); overload;  
  end;  
  
type  
    //共享对象工厂  
  TChessFactory = class  
  private  
    FDictionary: TDictionary<TColor, IChess>;  
  public  
    constructor Create(); overload;  
  
    function GetChess(Color: TColor): IChess;  
  
  end;  
  
implementation  
  
uses  
  System.SysUtils, System.TypInfo;  
{ TBlackChess }  
  
constructor TBlackChess.Create();  
begin  
  inherited;  
  //颜色赋值  
  FColor := TColor.BLACK;  
end;  
  
procedure TBlackChess.Draw(x, y: Integer);  
begin  
  var EnumName := GetEnumName(TypeInfo(TColor), 0);  
  
  Writeln(SHARP + EnumName + '棋子置于(' + inttostr(x) + ',' + inttostr(y) + ')处')  
end;  
  
{ TWhiteChess }  
  
constructor TWhiteChess.Create;  
begin  
  inherited;  
  //颜色赋值  
  FColor := TColor.WHITE;  
end;  
  
procedure TWhiteChess.Draw(x, y: Integer);  
begin  
  
  var EnumName := GetEnumName(TypeInfo(TColor), 1);  
  
  Writeln(SHARP + EnumName + '棋子置于(' + inttostr(x) + ',' + inttostr(y) + ')处')  
  
end;  
  
{ TChessFactory }  
  
constructor TChessFactory.Create;  
begin  
  FDictionary := TDictionary<TColor, IChess>.Create;  
end;  
  
function TChessFactory.GetChess(Color: TColor): IChess;  
begin  
  var Chess: IChess;  
  FDictionary.TryGetValue(Color, Chess);  
  if Chess = nil then  
  begin  
    if Color = TColor.WHITE then  
      Chess := TWhiteChess.Create  
    else  
      Chess := TBlackChess.Create;  
  
    FDictionary.Add(Color, Chess);  
  
  end;  
  Result := Chess;  
end;  
  
end.  

执行结果

从调用的情况看,下了 3 次黑棋,而每一次黑棋的内存地址都是相同的,说明并没有创建新的对象

结语

最后说一下设计模式是 1995 年,GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了 23 种设计模式,从此树立了软件设计模式领域的里程碑,人称「GoF 设计模式」

至此设计模式部分就彻底的完结了,虽然很多人不喜欢这个系列。接下来我暂时不知道该更新什么系列内容了,暂时定为网络编程吧!

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

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