首页 > 应用开发 > IT综合 > 转载---Dephi状态模式(State模式)
对于面向对象开发来说,很长的函数和过程是不容易维护的,同样冗长的if else 以及case of的条件判断语句会使得代码不够清晰,特别是当条件判断很多时,比如有几十条甚至十几条条件判断语句,会使得代码难以修改和维护。
在早期windows开发中,程序员经常需要编写巨大的消息判断语句,根据消息的不同调用不同的消息处理函数,后来为了改善消息处理的复杂程度,Delphi引入了message关键字,从编译器一级对消息处理进行了映射,减少了条件判断语句的大量使用,这一案例就是巨大的条件判断语句弊端的典型体现。
通常说来,if else 以及case 语句都是对对象的某个状态或者属性进行判断,根据对象的状态或属性的不同,执行不同的操作。实际上就是一个有限状态机,为了消除这些if else条件判断语句,我们可以使用State模式来解决。
[@more@]所谓状态模式就是将宿主对象中每一种可能的状态抽象成一个状态类,当宿主对象的状态发生变化时,宿主对象改变自己的状态,并执行不同状态类对应的不同操作。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;
MoveTo(TopLeft.X, TopLeft.Y);
LineTo(BottomRight.X, BottomRight.Y);
end;
end;
procedure TForm1.SetDrawingTool(const Value: TDrawingTool);
begin
FDrawingTool := Value;
end;
{ TDrawingTool }
constructor TDrawingTool.Create(AImage: TImage);
begin
FImage := AImage;
end;
end.
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/7416120/viewspace-968816/ ,如需转载,请注明出处,否则将追究法律责任。