《GOF设计模式》—适配器(ADAPTER)—Delphi源码示例:绘图编辑器

本文主要是介绍《GOF设计模式》—适配器(ADAPTER)—Delphi源码示例:绘图编辑器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


示例:绘图编辑器

说明:

有时,为复用而设计的工具箱类不能够被复用的原因仅仅是因为它的接口与专业应用领域所需要的接口不匹配。

例如,有一个绘图编辑器,这个编辑器允许用户绘制和排列基本图元(线、多边型和正

文等)、生成图片和图表。这个绘图编辑器的关键抽象是图形对象。图形对象有一个可编辑的形状,并可以绘制自身。图形对象的接口由一个称为Shape的抽象类定义。绘图编辑器为每一种图形对象定义了一个Shape的子类:LineShape类对应于直线,PolygonShape类对应于多边型,等等。

LineShapePolygonShape这样的基本几何图形的类比较容易实现,这是由于它们的绘图和编辑功能本来就很有限。但是对于可以显示和编辑正文的TextShape子类来说,实现相当困难,因为即使是基本的正文编辑也要涉及到复杂的屏幕刷新和缓冲区管理。同时,成品的用户界面工具箱可能已经提供了一个复杂的TextView类用于显示和编辑正文。理想的情况是我们可以复用这个TextView类以实现TextShape类,但是工具箱的设计者当时并没有考虑Shape的存在,因此TextViewShape对象不能互换。

一个应用可能会有一些类具有不同的接口并且这些接口互不兼容,在这样的应用中象TextView这样已经存在并且不相关的类如何协同工作呢?我们可以改变TextView类使它兼容Shape类的接口,但前提是必须有这个工具箱的源代码。然而即使我们得到了这些源代码,修改TextView也是没有什么意义的;因为不应该仅仅为了实现一个应用,工具箱就不得不采用一些与特定领域相关的接口。

我们可以不用上面的方法,而定义一个TextShape类,由它来适配TextView的接口和Shape的接口。我们可以用两种方法做这件事:1)、继承Shape类的接口和TextView的实现,或2)、将一个TextView实例作为TextShape的组成部分,并且使用TextView的接口实现TextShape。这两种方法恰恰对应于Adapter模式的类和对象版本。我们将TextShape称之为适配器Adapter

上面的类图说明了对象适配器实例。它说明了在Shape类中声明的BoundingBox请求如何被转换成在TextView类中定义的GetExtent请求。由于TextShapeTextView的接口与Shape的接口进行了匹配,因此绘图编辑器就可以复用原先并不兼容的TextView类。

Adapter时常还要负责提供那些被匹配的类所没有提供的功能,上面的类图中说明了适配器如何实现这些职责。由于绘图编辑器允许用户交互的将每一个Shape对象“拖动”到一个新的位置,而TextView设计中没有这种功能。我们可以实现TextShape类的CreateManipulator操作,从而增加这个缺少的功能,这个操作返回相应的Manipulator子类的一个实例。

Manipulator是一个抽象类,它所描述的对象知道如何驱动Shape类响应相应的用户输入,例如将图形拖动到一个新的位置。对应于不同形状的图形,Manipulator有不同的子类;例如子类TextManipulator对应于TextShapeTextShape通过返回一个TextManipulator实例,增加了TextView中缺少而Shape需要的功能。

从类ShapeTextView开始,我们将给出类适配器和对象适配器实现代码的简要框架。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源码示例:绘图编辑器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1142330

相关文章

Python如何去除图片干扰代码示例

《Python如何去除图片干扰代码示例》图片降噪是一个广泛应用于图像处理的技术,可以提高图像质量和相关应用的效果,:本文主要介绍Python如何去除图片干扰的相关资料,文中通过代码介绍的非常详细,... 目录一、噪声去除1. 高斯噪声(像素值正态分布扰动)2. 椒盐噪声(随机黑白像素点)3. 复杂噪声(如伪

Java Spring ApplicationEvent 代码示例解析

《JavaSpringApplicationEvent代码示例解析》本文解析了Spring事件机制,涵盖核心概念(发布-订阅/观察者模式)、代码实现(事件定义、发布、监听)及高级应用(异步处理、... 目录一、Spring 事件机制核心概念1. 事件驱动架构模型2. 核心组件二、代码示例解析1. 事件定义

python使用库爬取m3u8文件的示例

《python使用库爬取m3u8文件的示例》本文主要介绍了python使用库爬取m3u8文件的示例,可以使用requests、m3u8、ffmpeg等库,实现获取、解析、下载视频片段并合并等步骤,具有... 目录一、准备工作二、获取m3u8文件内容三、解析m3u8文件四、下载视频片段五、合并视频片段六、错误

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

mysql中insert into的基本用法和一些示例

《mysql中insertinto的基本用法和一些示例》INSERTINTO用于向MySQL表插入新行,支持单行/多行及部分列插入,下面给大家介绍mysql中insertinto的基本用法和一些示例... 目录基本语法插入单行数据插入多行数据插入部分列的数据插入默认值注意事项在mysql中,INSERT I

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF

MyBatis ResultMap 的基本用法示例详解

《MyBatisResultMap的基本用法示例详解》在MyBatis中,resultMap用于定义数据库查询结果到Java对象属性的映射关系,本文给大家介绍MyBatisResultMap的基本... 目录MyBATis 中的 resultMap1. resultMap 的基本语法2. 简单的 resul