08状态模式.doc_第1页
08状态模式.doc_第2页
08状态模式.doc_第3页
08状态模式.doc_第4页
08状态模式.doc_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Dephi状态模式(State模式)作者 陈省对于面向对象开发来说,很长的函数和过程是不容易维护的,同样冗长的if else 以及case of的条件判断语句会使得代码不够清晰,特别是当条件判断很多时,比如有几十条甚至十几条条件判断语句,会使得代码难以修改和维护。在早期windows开发中,程序员经常需要编写巨大的消息判断语句,根据消息的不同调用不同的消息处理函数,后来为了改善消息处理的复杂程度,Delphi引入了message关键字,从编译器一级对消息处理进行了映射,减少了条件判断语句的大量使用,这一案例就是巨大的条件判断语句弊端的典型体现。通常说来,if else 以及case 语句都是对对象的某个状态或者属性进行判断,根据对象的状态或属性的不同,执行不同的操作。实际上就是一个有限状态机,为了消除这些if else条件判断语句,我们可以使用State模式来解决。所谓状态模式就是将宿主对象中每一种可能的状态抽象成一个状态类,当宿主对象的状态发生变化时,宿主对象改变自己的状态,并执行不同状态类对应的不同操作。以圣斗士星矢为例,当他的小宇宙处于不同的状态时,他发出的天马流星拳、天狗流星拳、天鹅流星拳具有不同的威力,分别对应于青铜圣斗士,白银圣斗士,黄金圣斗士的级别。对星矢进行建模后的UML图示意如下:比较一下使用State模式前后的不同,没有使用State模式前,星矢使用天马流星拳等招数的伪代码:procedure 星矢.天马流星拳;begin case 小宇宙 of 黄金圣斗士: 打出黄金圣斗士威力的天马流星拳 白银圣斗士:打出白银圣斗士威力的天马流星拳 青铜圣斗士:打出青铜圣斗士威力的天马流星拳 end;end;procedure 星矢.天狗流星拳;begin case 小宇宙 of 黄金圣斗士: 打出黄金圣斗士威力的天狗流星拳 白银圣斗士:打出白银圣斗士威力的天狗流星拳 青铜圣斗士:打出青铜圣斗士威力的天狗流星拳 end;end;procedure 星矢.天鹅流星拳;begin case 小宇宙 of 黄金圣斗士: 打出黄金圣斗士威力的天鹅流星拳 白银圣斗士:打出白银圣斗士威力的天鹅流星拳 青铜圣斗士:打出青铜圣斗士威力的天鹅流星拳 end;end;使用State模式后,星矢使用天马流星拳等招数的伪代码示意如下:/设定小宇宙状态星矢.小宇宙:=黄金圣斗士;procedure 星矢.天马流星拳;begin 小宇宙.天马流星拳end;procedure 星矢.天狗流星拳;begin 小宇宙.天狗流星拳end;procedure 星矢.天鹅流星拳;begin 小宇宙.天鹅流星拳end;可以看到宿主对象的代码简化了许多,同时消除了case条件判断语句,同时使用State模式的好处还在于便于扩充和修改,比如要调整黄金圣斗士的天马流星拳的威力,只要修改黄金圣斗士小宇宙对象的相应方法就可以了,不用象以前那样在一个case语句中寻找相应的状态对应的代码。同时便于扩充,比如客户觉得有必要给星矢增加一个小宇宙状态,比如超级塞亚人小宇宙,在不改动宿主对象代码的情况,只要添加一个新类就可以了,宿主对象的所有同小宇宙相关的招数方法都无须改变,而使用case条件判断语句的话,则需要在每一个招数方法中添加新的判断,如果星矢会的招数太多的话,修改的地方就是大量的了。虽然State模式有上面的优点,但是它也有它的缺点,就是如果宿主对象的状态比较多的话,会产生大量的小粒度的对象,显得对象过多,体系不紧凑。另外,State模式的模型图和策略模式的模型图几乎一样,区别在于状态模式的特点是状态会经常发生变化,而策略模式一般来说在使用的时候通常是固定的,不会频繁变化。另外两个模式的目的也不同,对状态改变时,对象具有不同的行为进行抽象,对应于State模式。而策略模式则是为了解决算法的互换问题的。状态模式使用示例在Delphi的demosdocgraphex目录下,提供了一个画图程序的例子,运行后可以根据当前绘图工具的不同,绘制不同的形状,示意图如下:其中核心的绘图部分就是一个大的添加判断过程DrawShape,根据当前绘图工具的不同(线、圆、矩形、圆角矩形),绘制不同的形状,代码如下:procedure TForm1.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);begin with Image.Canvas do begin Pen.Mode := AMode; case DrawingTool of dtLine: begin Image.Canvas.MoveTo(TopLeft.X, TopLeft.Y); Image.Canvas.LineTo(BottomRight.X, BottomRight.Y); end; dtRectangle: Image.Canvas.Rectangle(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); dtEllipse: Image.Canvas.Ellipse(Topleft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); dtRoundRect: Image.Canvas.RoundRect(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y, (TopLeft.X - BottomRight.X) div 2, (TopLeft.Y - BottomRight.Y) div 2); end; end;end;下面我们就对这一例子使用State模式进行改造,消除Case判断。首先对系统建模:修改后的代码如下:type TDrawingTool = class(TObject) private FImage: TImage; public constructor Create(AImage: TImage); procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode); virtual; abstract; end; TLineTool = class(TDrawingTool) procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode); override; end; TRectTool = class(TDrawingTool) procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode); override; end; TRoundRectTool = class(TDrawingTool) procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode); override; end; TEllipseTool = class(TDrawingTool) procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode); override; end; TForm1 = class(TForm) private FDrawingTool: TDrawingTool; procedure SetDrawingTool(const Value: TDrawingTool); Private declarations public Public declarations procedure DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode); property DrawingTool: TDrawingTool read FDrawingTool write SetDrawingTool; end;procedure TForm1.LineButtonClick(Sender: TObject);begin FreeAndNil(FDrawingTool); DrawingTool := TLineTool.Create(Image);end;procedure TForm1.RectangleButtonClick(Sender: TObject);begin FreeAndNil(FDrawingTool); DrawingTool := TRectTool.Create(Image);end;procedure TForm1.EllipseButtonClick(Sender: TObject);begin FreeAndNil(FDrawingTool); DrawingTool := TEllipseTool.Create(Image);end;procedure TForm1.RoundRectButtonClick(Sender: TObject);begin FreeAndNil(FDrawingTool); DrawingTool := TRoundRectTool.Create(Image);end;procedure TForm1.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);begin DrawingTool.DrawShape(TopLeft, BottomRight, AMode);end;procedure TForm1.FormCreate(Sender: TObject);begin LineButton.OnClick(nil);end; TEllipseTool procedure TEllipseTool.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);begin with FImage.Canvas do begin Pen.Mode := AMode; Ellipse(Topleft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); end;end; TRoundRectTool procedure TRoundRectTool.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);begin with FImage.Canvas do begin Pen.Mode := AMode; RoundRect(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y, (TopLeft.X - BottomRight.X) div 2, (TopLeft.Y - BottomRight.Y) div 2); end;end; TRectTool procedure TRectTool.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);begin with FImage.Canvas do begin Pen.Mode := AMode; Rectangle(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); end;end; TLineTool procedure TLineTool.DrawShape(TopLeft, BottomRight: TPoint; AMode: TPenMode);begin with FImage.Canvas do begin Pen.Mode := AMode;

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论