本文主要是介绍《GOF设计模式》—适配器(ADAPTER)—Delphi源码示例:绘图编辑器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
示例:绘图编辑器
说明:
有时,为复用而设计的工具箱类不能够被复用的原因仅仅是因为它的接口与专业应用领域所需要的接口不匹配。
例如,有一个绘图编辑器,这个编辑器允许用户绘制和排列基本图元(线、多边型和正
文等)、生成图片和图表。这个绘图编辑器的关键抽象是图形对象。图形对象有一个可编辑的形状,并可以绘制自身。图形对象的接口由一个称为Shape的抽象类定义。绘图编辑器为每一种图形对象定义了一个Shape的子类:LineShape类对应于直线,PolygonShape类对应于多边型,等等。
像LineShape和PolygonShape这样的基本几何图形的类比较容易实现,这是由于它们的绘图和编辑功能本来就很有限。但是对于可以显示和编辑正文的TextShape子类来说,实现相当困难,因为即使是基本的正文编辑也要涉及到复杂的屏幕刷新和缓冲区管理。同时,成品的用户界面工具箱可能已经提供了一个复杂的TextView类用于显示和编辑正文。理想的情况是我们可以复用这个TextView类以实现TextShape类,但是工具箱的设计者当时并没有考虑Shape的存在,因此TextView和Shape对象不能互换。
一个应用可能会有一些类具有不同的接口并且这些接口互不兼容,在这样的应用中象TextView这样已经存在并且不相关的类如何协同工作呢?我们可以改变TextView类使它兼容Shape类的接口,但前提是必须有这个工具箱的源代码。然而即使我们得到了这些源代码,修改TextView也是没有什么意义的;因为不应该仅仅为了实现一个应用,工具箱就不得不采用一些与特定领域相关的接口。
我们可以不用上面的方法,而定义一个TextShape类,由它来适配TextView的接口和Shape的接口。我们可以用两种方法做这件事:1)、继承Shape类的接口和TextView的实现,或2)、将一个TextView实例作为TextShape的组成部分,并且使用TextView的接口实现TextShape。这两种方法恰恰对应于Adapter模式的类和对象版本。我们将TextShape称之为适配器Adapter。
上面的类图说明了对象适配器实例。它说明了在Shape类中声明的BoundingBox请求如何被转换成在TextView类中定义的GetExtent请求。由于TextShape将TextView的接口与Shape的接口进行了匹配,因此绘图编辑器就可以复用原先并不兼容的TextView类。
Adapter时常还要负责提供那些被匹配的类所没有提供的功能,上面的类图中说明了适配器如何实现这些职责。由于绘图编辑器允许用户交互的将每一个Shape对象“拖动”到一个新的位置,而TextView设计中没有这种功能。我们可以实现TextShape类的CreateManipulator操作,从而增加这个缺少的功能,这个操作返回相应的Manipulator子类的一个实例。
Manipulator是一个抽象类,它所描述的对象知道如何驱动Shape类响应相应的用户输入,例如将图形拖动到一个新的位置。对应于不同形状的图形,Manipulator有不同的子类;例如子类TextManipulator对应于TextShape。TextShape通过返回一个TextManipulator实例,增加了TextView中缺少而Shape需要的功能。
从类Shape和TextView开始,我们将给出类适配器和对象适配器实现代码的简要框架。Shape假定有一个边框,这个边框由它相对的两角定义。而TextView则由原点、宽度和高度定义。Shape同时定义了CreateManipulator操作用于创建一个Manipulator对象。当用户操作一个图形时,Manipulator对象知道如何驱动这个图形。TextView没有等同的操作。TextShape类是这些不同接口间的适配器。
对象适配器采用对象组合的方法将具有不同接口的类组合在一起。在该方法中,适配器TextShape维护一个指向TextView的指针。TextShape必须在构造器中对指向TextView实例的指针进行初始化,当它自身的操作被调用时,它还必须对它的TextView对象调用相应的操作。在本例中,假设客户创建了TextView对象并且将其传递给TextShape的构造器。
代码:
unit uDrawingEdtior;
interface
uses
Windows,Classes,Graphics;
type
TManipulator = class;
TTextView = class;
{图形对象}
TShape = class
private
FCanvas: TCanvas;
public
{获取图形边界}
procedure BoundingBox(var LeftTop,RightBottom: TPoint); virtual; abstract;
{获取图形操作对象:工厂方法}
function CreateManipulator(): TManipulator; virtual; abstract;
procedure Draw; virtual; abstract;
//---
property Canvas: TCanvas read FCanvas write FCanvas;
end;
{直线}
TLineShape = class(TShape)
private
FLeftTop,FRightBottom: TPoint;
public
constructor Create;
//---
procedure BoundingBox(var LeftTop,RightBottom: TPoint); override;
function CreateManipulator: TManipulator; override;
procedure Draw; override;
end;
{多边型}
TPolygonShape = class(TShape)
private
FLeftTop,FRightBottom: TPoint;
public
constructor Create;
//---
procedure BoundingBox(var LeftTop,RightBottom: TPoint); override;
function CreateManipulator: TManipulator; override;
procedure Draw; override;
end;
{文本}
TTextShape = class(TShape)
private
FTextView: TTextView;
public
constructor Create(ATextView: TTextView);
//---
procedure BoundingBox(var LeftTop,RightBottom: TPoint); override;
function CreateManipulator(): TManipulator; override;
procedure Draw; override;
function IsEmpty: Boolean;
end;
{图形操作对象:依据使用端控制驱动图形对象}
TManipulator = class
private
FShape: TShape;
public
constructor Create(AShape: TShape);
//---
procedure Operate; virtual; abstract;
end;
TLineManipulator = class(TManipulator)
public
procedure Operate; override;
end;
TPolygonManipulator = class(TManipulator)
public
procedure Operate; override;
end;
TTextManipulator = class(TManipulator)
public
procedure Operate; override;
end;
{文本视图}
TTextView = class
public
{获取原点}
procedure GetOrigin(var X,Y: Longint);
{获取高宽:定义显示对象自原点计算之高及宽}
procedure GetExtent(var width,height: Longint);
function IsEmpty(): Boolean;
end;
procedure ClearBackground(ACanvas: TCanvas);
implementation
procedure ClearBackground(ACanvas: TCanvas);
begin
with ACanvas do
begin
with Brush do
begin
Color := clBlack;
Style := bsSolid;
end;
FillRect(ClipRect);
end;
end;
constructor TManipulator.Create(AShape: TShape);
begin
FShape := AShape;
end;
procedure TTextView.GetOrigin(var X,Y: Longint);
begin
X := 20;
Y := 80;
end;
procedure TTextView.GetExtent(var width,height: Longint);
begin
width := 10;
height := 10;
end;
function TTextView.IsEmpty(): Boolean;
begin
Result := True;
end;
constructor TTextShape.Create(ATextView: TTextView);
begin
inherited Create;
//---
FTextView := ATextView;
end;
procedure TTextShape.BoundingBox(var LeftTop,RightBottom: TPoint);
var
left,top,width,height: integer;
begin
FTextView.GetOrigin(left,top);
FTextView.GetExtent(width,height);
//---
LeftTop.x := left;
LeftTop.y := top;
//---
RightBottom.x := left + width;
RightBottom.y := top + height;
end;
function TTextShape.CreateManipulator(): TManipulator;
begin
result := TTextManipulator.Create(self);
end;
procedure TTextShape.Draw;
var
X,Y: integer;
begin
FTextView.GetOrigin(X,Y);
with self.Canvas do
begin
Font.Color := clYellow;
TextOut(X,Y, '123');
end;
end;
function TTextShape.IsEmpty: Boolean;
begin
result := FTextView.IsEmpty;
end;
procedure TLineShape.BoundingBox(var LeftTop,RightBottom: TPoint);
begin
LeftTop := FLeftTop;
RightBottom := FRightBottom;
end;
constructor TLineShape.Create;
begin
inherited;
//---
FLeftTop.x := 10;
FLeftTop.y := 10;
FRightBottom.x := FLeftTop.x + 20;
FRightBottom.y := FLeftTop.y + 20;
end;
function TLineShape.CreateManipulator: TManipulator;
begin
result := TLineManipulator.Create(self);
end;
procedure TLineShape.Draw;
begin
with self.Canvas do
begin
with Pen do
begin
Color := clYellow;
Style := psSolid;
Width := 1;
Mode := pmXor;
end;
//---
with FLeftTop do
MoveTo(X,Y);
with FRightBottom do
LineTo(X,Y);
end;
end;
constructor TPolygonShape.Create;
begin
inherited;
//---
FLeftTop.x := 50;
FLeftTop.y := 50;
FRightBottom.x := FLeftTop.x + 40;
FRightBottom.y := FLeftTop.y + 40;
end;
procedure TPolygonShape.BoundingBox(var LeftTop,RightBottom: TPoint);
begin
LeftTop := FLeftTop;
RightBottom := FRightBottom;
end;
function TPolygonShape.CreateManipulator: TManipulator;
begin
result := TPolygonManipulator.Create(self);
end;
procedure TPolygonShape.Draw;
var
pts: array[0..2] of TPoint;
begin
with self.Canvas do
begin
with Pen do
begin
Color := clYellow;
Style := psSolid;
Width := 1;
Mode := pmXor;
end;
//---
pts[0] := FLeftTop;
pts[1].X := FRightBottom.X;
pts[1].Y := FLeftTop.Y;
pts[2] := FRightBottom;
//---
Polygon(pts);
end;
end;
procedure TLineManipulator.Operate;
var
LeftTop,RightBottom: TPoint;
begin
with FShape.Canvas do
begin
with Pen do
begin
Width := 1;
Color := clRed;
Style := psSolid;
Mode := pmXor;
end;
Brush.Style := bsClear;
//---
FShape.BoundingBox(LeftTop,RightBottom);
Rectangle(LeftTop.x,LeftTop.y,RightBottom.x,RightBottom.y);
end;
end;
procedure TPolygonManipulator.Operate;
var
LeftTop,RightBottom: TPoint;
begin
with FShape.Canvas do
begin
with Pen do
begin
Width := 1;
Color := clRed;
Style := psDot;
Mode := pmXor;
end;
Brush.Style := bsClear;
//---
FShape.BoundingBox(LeftTop,RightBottom);
Rectangle(LeftTop.x,LeftTop.y,RightBottom.x,RightBottom.y);
end;
end;
procedure TTextManipulator.Operate;
var
LeftTop,RightBottom: TPoint;
begin
with FShape.Canvas do
begin
with Pen do
begin
Width := 1;
Color := clRed;
Style := psDashDotDot;
Mode := pmXor;
end;
Brush.Style := bsClear;
//---
FShape.BoundingBox(LeftTop,RightBottom);
Rectangle(LeftTop.x,LeftTop.y,RightBottom.x,RightBottom.y);
end;
end;
end.
unit Unit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls,ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses uAdapter,uDrawingEdtior;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
//---
procedure _DrawShape(AShape: TShape);
var
AManipulator: TManipulator;
begin
AShape.Canvas := Image1.Canvas;
AShape.Draw;
//---
AManipulator := AShape.CreateManipulator;
AManipulator.Operate;
AManipulator.Free;
//---
AShape.Free;
end;
var
ATextView: TTextView;
begin
ClearBackground(Image1.Canvas);
//---
_DrawShape(TLineShape.Create);
_DrawShape(TPolygonShape.Create);
//---
ATextView := TTextView.Create;
_DrawShape(TTextShape.Create(ATextView));
ATextView.Free;
end;
end.
这篇关于《GOF设计模式》—适配器(ADAPTER)—Delphi源码示例:绘图编辑器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!